一、事务&&JDBC事务支持
在我的之前的spring操作数据库中的文章很少提及事务,不是说它不重要,而是太重要,以至于spring专门有一部分来说明这一内容。之前可以说对事务几乎没有考虑过,只是知道把要进行的操作被事务包裹起来,就像在hibernate中进行的操作一样,如下:
Session session = factory.openSession();
Transaction transaction = session.beginTransaction();
session.save(...);
transaction.commit();
session.close();
另外知道事务是保证操作的原子性,即ACID中的那个A。所以关于事务的内容提前看了好多,看如下的第一个链接。
另外JDBC也提供了对数据库事务的操作,典型的JDBC事务数据操作如下:
try {
Class.forName("");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
Savepoint savepoint = null;
try {
conn = DriverManager.getConnection("");
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Statement statement = conn.createStatement();
statement.executeQuery("sql1");
savepoint = conn.setSavepoint("sql1");
statement.executeQuery("sql2");
conn.commit();
} catch (SQLException e) {
try {
if(savepoint == null){
conn.rollback();
}
else{
conn.rollback(savepoint);
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
JDBC中的Connection是默认自动提交的,也就是每执行一条SQL语句就对应一个事务,所以我们首先要禁止掉让它默认提交,所以设置为setAutoCommit(false),如果发生运行时异常则会发生回滚rollback(),另外还可以通过setTransactionIsolation()设置隔离级别(至于什么是隔离级别,看如下的相关文章)。另外还有一点在我写这篇之前我是不知道还有保存点这回事的,什么是保存点呢?也就是一个事务中可能要执行多个SQL语句,之前回滚的时候只能回滚到执行所有SQL之前,但是现在我们可以只回滚到执行某个SQL语句之前,而不必要撤销所有的SQL语句,如上面SavePoint 的使用。
二、Spring对事务的支持初步
Spring对事务的支持可以分成两种,一是
编程式事务管理,什么意思,说白了就是写代码实现事务管理,就是向我们上边的JDBC对事务的管理的方式,每执行一次对数据库的操作都要加上事务的模板代码;一种是
声明式事务管理,就是通过注解和XML配置文件的方式来完成对事务的管理,就像我们前面中说到的对Bean管理,可以想象一下通过什么样的手段来完成这种类型的事务管理?前面我们说到AOP这种思想,可以想象我们可以通过这种手段来实现把对数据库的操作放到一个类似于容器(自造)中来管理。Spring实际上就是通过AOP来完成对事务的管理的。
Spring提供了一种事务机制,这种机制不管底层的实现具体是JDBC,还是Hibernate、myBatis等,它的处理方式都是类似的,也就是Spring构建了一个抽象层,
能够和底层具体的事务技术相独立,这就为我们提供了方便。
Spring的核心事务管理对象是PlatformTransactionManager,它只提供了三个方法,其中我们熟悉的有commit()和rollback()。它有一个实现类AbstractPlatformTransactionManager,这个实现类也有两个实现类:
- DataSourceTransactionManager:管理一个数据源,并且通过JDBC来完成对数据库的操作;
- JtaTransactionManager:使用JTA进行事务管理;
以上的事务管理器的使用方式:
<!-- config transaction manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- enable transaction annotation -->
<tx:annotation-driven transaction-manager="transactionManager"/>
首先配置事务管理器,它需要一个数据源属性,然后开启事务注解,属性transaction-manager的值也是transactionManager,如果
默认是这个值则不需要配置这个属性。
public class PersonDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional
public void update(int age){
jdbcTemplate.update("insert into user(username, address, age) values(?,?,?)", "abc", "hz", age);
if(age < 20){
throw new OperationException("");
}
}
}
使用@Transactional来标识到一个方法,我们的自定义一个运行时异常(
注意只有RuntimeException才会rollback),可以看到方法发生异常的时候数据不会插入,但是没有该注解,则会插入数据并会报出异常。
相关文章: