Spring事务管理与JdbcTemplate实战

在现代的Java企业级应用开发中,Spring框架的事务管理功能是不可或缺的一部分。它通过高度抽象的PlatformTransactionManager接口,将底层的事务机制封装起来,使得开发者可以专注于业务逻辑的实现,而无需过多关心事务的具体实现细节。本文将通过一个具体的实例,深入探讨Spring框架中事务管理的使用方法,并结合JdbcTemplate完成数据库操作。
一、Spring事务管理的核心:PlatformTransactionManager
PlatformTransactionManager是Spring事务管理的核心接口,它定义了事务的基本操作,如开始事务、提交事务和回滚事务等。Spring提供了多种PlatformTransactionManager的实现,其中DataSourceTransactionManager是针对单个JDBC DataSource的事务管理器实现。它利用java.sql.Connection提供的事务功能,适用于简单的JDBC操作场景。
二、实例:基于Spring和JdbcTemplate的订单管理系统

  1. 数据访问层:OrderItemJdbcTemplateDao
    在本实例中,我们定义了一个OrderItemJdbcTemplateDao类,用于实现对订单项(OrderItem)的数据库操作。该类通过JdbcTemplate与数据库进行交互,以下是其核心代码:
    java复制
    @Component
    public class OrderItemJdbcTemplateDao implements Dao {
    @Autowired
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    private void postConstruct() {
    jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public long save(OrderItem orderItem) {
    String sql = “insert into ORDER_ITEM (ITEM, QTY) values (?, ?)”;
    KeyHolder holder = new GeneratedKeyHolder();
    jdbcTemplate.update(new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection connection)
    throws SQLException {
    PreparedStatement ps = connection.prepareStatement(sql.toString(),
    Statement.RETURN_GENERATED_KEYS);
    ps.setString(1, orderItem.getItem());
    ps.setInt(2, orderItem.getQty());
    return ps;
    }
    }, holder);
    Number key = holder.getKey();
    if (key != null) {
    return key.longValue();
    }
    throw new RuntimeException(“No generated primary key returned.”);
    }

    @Override
    public OrderItem load(long id) {
    List items = jdbcTemplate.query(“select * from ORDER_ITEM where id =?”,
    new Object[]{id}, (resultSet, i) -> {
    return toOrderItem(resultSet);
    });
    if (items.size() == 1) {
    return items.get(0);
    }
    throw new RuntimeException("No item found for id: " + id);
    }

    @Override
    public List loadAll() {
    return jdbcTemplate.query(“select * from ORDER_ITEM”, (resultSet, i) -> {
    return toOrderItem(resultSet);
    });
    }

    private OrderItem toOrderItem(ResultSet resultSet) throws SQLException {
    OrderItem orderItem = new OrderItem();
    orderItem.setId(resultSet.getLong(“ID”));
    orderItem.setItem(resultSet.getString(“ITEM”));
    orderItem.setQty(resultSet.getInt(“QTY”));
    return orderItem;
    }
    }

  2. 配置事务管理器:AppConfig
    为了使用Spring的事务管理功能,我们需要配置一个PlatformTransactionManager的实现。在本例中,我们使用DataSourceTransactionManager,并通过@Configuration注解定义了相关的配置类:
    java复制
    @Configuration
    @ComponentScan
    public class AppConfig {
    @Bean
    public DataSource h2DataSource() {
    return new EmbeddedDatabaseBuilder()
    .setType(EmbeddedDatabaseType.H2)
    .addScript(“createOrderItemTable.sql”)
    .build();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(h2DataSource());
    return transactionManager;
    }
    }
    同时,我们在src/main/resources目录下定义了createOrderItemTable.sql脚本,用于创建订单项表:
    sql复制
    CREATE TABLE ORDER_ITEM(
    ID BIGINT PRIMARY KEY AUTO_INCREMENT,
    ITEM VARCHAR(255) NOT NULL,
    QTY INT NOT NULL check (QTY > 0 and QTY <= 100)
    );

  3. 事务操作:OrderItemClientBean
    在业务逻辑层,我们通过OrderItemClientBean类来演示事务的使用。以下是其核心代码:
    java复制
    @Component
    public class OrderItemClientBean {
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private Dao dao;

    public void persistOrderItems() {
    TransactionStatus ts =
    transactionManager.getTransaction(new DefaultTransactionDefinition());
    try {
    long id = dao.save(new OrderItem(“BWell Ethernet Cable”, 5));
    System.out.println(“id generated: " + id);
    id = dao.save(new OrderItem(“EDrive SSD”, 2000));
    System.out.println(“id generated: " + id);
    transactionManager.commit(ts);
    } catch (Exception e) {
    transactionManager.rollback(ts);
    System.out.println(”-- exception message --”);
    System.err.println(e.getMessage());
    System.out.println(“---------”);
    }
    System.out.println(“loaded items: " + dao.loadAll());
    System.out.println(”-- second attempt --");

     ts = transactionManager.getTransaction(new DefaultTransactionDefinition());
     try {
         long id = dao.save(new OrderItem("BWell Ethernet Cable", 5));
         System.out.println("id generated: " + id);
         id = dao.save(new OrderItem("EDrive SSD", 20));
         System.out.println("id generated: " + id);
         transactionManager.commit(ts);
     } catch (Exception e) {
         transactionManager.rollback(ts);
         System.out.println("-- exception message --");
         System.err.println(e.getMessage());
         System.out.println("---------");
     }
     System.out.println("loaded items: " + dao.loadAll());
    

    }
    }
    在上述代码中,我们首先尝试插入两个订单项,其中一个订单项的数量超出了数据库表中定义的范围(QTY必须在1到100之间),这将导致事务回滚。随后,我们再次尝试插入两个符合要求的订单项,这次事务将成功提交。

  4. 主程序入口:ExampleMain
    最后,我们通过ExampleMain类启动应用程序:
    java复制
    public class ExampleMain {
    public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
    new AnnotationConfigApplicationContext(AppConfig.class);
    OrderItemClientBean orderItemClientBean = context.getBean(OrderItemClientBean.class);
    orderItemClientBean.persistOrderItems();
    }
    }
    三、运行结果
    运行程序后,输出如下:
    复制
    id generated: 1
    – exception message –
    PreparedStatementCallback; SQL []; Check constraint violation: “((QTY > 0) AND (QTY <= 100))”; SQL statement:
    insert into ORDER_ITEM (ITEM, QTY) values (?, ?) [23513-196]; nested exception is org.h2.jdbc.JdbcSQLException: Check constraint violation: “((QTY > 0) AND (QTY <= 100))”; SQL statement:
    insert into ORDER_ITEM (ITEM, QTY) values (?, ?) [23513-196]


loaded items: []
– second attempt –
id generated: 3
id generated: 4
loaded items: [OrderItem{id=3, item=‘BWell Ethernet Cable’, qty=5}, OrderItem{id=4, item=‘EDrive SSD’, qty=20}]
从输出结果可以看出,第一次事务由于违反了数据库的检查约束而回滚,第二次事务成功提交。
四、总结
通过本文的实例,我们详细介绍了Spring框架中PlatformTransactionManager的使用方法,并结合JdbcTemplate完成了数据库的增删改查操作。在实际开发中,事务管理是确保数据一致性的关键环节。Spring提供的事务抽象机制,使得开发者可以轻松地在不同的事务环境中进行切换,极大地提高了开发效率。希望本文能够帮助读者更好地理解和使用Spring的事务管理功能。

你可能感兴趣的:(spring,数据库,sql,个人开发)