Java事务详解
1 public int delete(int sID) {
2 dbc = new DataBaseConnection();
3 Connection con = dbc.getConnection();
4 try {
5 con.setAutoCommit(false);// 更改JDBC事务的默认提交方式
6 dbc.executeUpdate("delete from xiao where ID=" + sID);
7 dbc.executeUpdate("delete from xiao_content where ID=" + sID);
8 dbc.executeUpdate("delete from xiao_affix where bylawid=" + sID);
9 con.commit();//提交JDBC事务
10 con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式
11 dbc.close();
12 return 1;
13 } catch (Exception exc) {
14 con.rollBack();//回滚JDBC事务
15 exc.printStackTrace();
16 dbc.close();
17 return -1;
18 }
19 }
在数据库操作中,一项事务是指由一条或多条对数据库写操作的sql语句所组成的一个不可分割的工作单元。只有当事务中的所有操作都正常完成了,整个事务才能被提交到数据库,如果有一项操作失败没有完成,就必须回滚撤消整个事务。
例如在银行的转帐事务中,假定张三从自己的帐号上把1000元转到李四的帐号上,相关的sql语句如下:update account set monery=monery-1000 where name='zhangsan'update account set monery=monery+1000 where name='lisi'这两条语句必须作为一个完整的事务来处理。只有当两条都成功执行了,才能提交这个事务。如果有一条失败,整个事务必须撤消回滚。
四、SQL 标准定义了四种事务隔离级别,MySQL 全都支持。这四种隔离级别分别是:
(事务的隔离级别是指若干个并发的事务之间的隔离程度)
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
②读未提交(READ UNCOMMITTED):该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读。
③读提交 (READ COMMITTED):该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读。
④可重复读 (REPEATABLE READ):该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
⑤串行化 (SERIALIZABLE):所有事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读和幻读。但是这将严重影响程序的性能。
隔离级别脏读不可重复读幻读
读未提交(Read uncommitted)
可能
可能
可能
读提交(Read committed)
不可能
可能
可能
可重复读(Repeatable reads)
不可能
不可能
可能
串行化(Serializable)
不可能
不可能
不可能
以下几个概念是事务隔离级别要实际解决的问题:脏读,不可重复读,幻读。
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的就是脏数据。
2、不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
3、幻读:事务A对数据库的数据进行批量操作。事务B完成记录的添加,这时新加的记录可能就没有进行事务A的批量操作。
五、事务传播行为
spring事务的传播机制说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。
@Transactional 注解的 propagation 属性,用于定义事务传播行为 @Transactional( propagation = Propagation.REQUIRED)
Propagation.REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
Propagation.REQUIRES_NEW:创建一个新的食物,如果当前存在事务,则把当前事务挂起。
Propagation.SUPPORTS:如果当前存在事务 ,则加入该事务;如果当前没有事务,则以非事务方式继续运行。
Propagation.NOT_SUPPORTS:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。
Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
Propagation.MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
@Transactional(isolation = Isolation.READ_COMMITTED)注解的 isolation 属性,用于定义事务隔离级别。
六、分布式事务
(1)JTA(Java Transaction API)
在应用系统数据量越来越大时,系统数据就需要分布在不同的数据库中,当业务需求在多个数据库中做原子性操作时就可以选择JTA (Java Transaction API),JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。
(2)JTA原理
不同的数据库有不同的数据库供应商,JTA就是将这个不同的数据库管理起来,统一创建一个原子事务,全部成功即成功,一个不成功就回滚所有的操作(JTA还是较重量级)
(3)实例
Spring有很多的JTA框架,这里使用的是atomikos框架。
(4)分布式消息最终一致性事务实现原理
当应用收到请求,应用会先将用户请求的数据保存到分布式消息中间件中,做一个保存操作。保存成功后就给用户返回提交成功信息。接着分布式消息中间件将请求在发送到不同的处理机器上,处理机器收到消息在进行业务处理。比如A给B转账,A先提交转账信息(已经扣款),然后消息被发送的分布式消息中间件上,消息中间件在发送到处理机器上面做处理,转账成功后则在给用户发送转账成功信息,不成功则把款退回去。
七、事务的属性可同通过注解方式或配置文件配置:
1、注解方式:
@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
默认情况下,一个有事务方法, 遇到RuntimeException 时会回滚 . 遇到 受检查的异常 是不会回滚 的. 要想所有异常都回滚,要加上 @Transactional( rollbackFor={IOException.class,其它异常})
1 @Transactional(
2 readOnly = false, //读写事务
3 timeout = -1 , //事务的超时时间,-1为无限制
4 noRollbackFor = ArithmeticException.class, //遇到指定的异常不回滚
5 isolation = Isolation.DEFAULT, //事务的隔离级别,此处使用后端数据库的默认隔离级别
6 propagation = Propagation.REQUIRED //事务的传播行为
7 )
2、配置文件( aop拦截器方式):
1
2
3
18
19
20
21
22
23
24