使用的条件及需要注意的事项:
1.使用必须是java5或者以上;
2.@Transactional都是用在public修饰的可见类或者方法上面,如果在 private,protected 上使用的话,不会报错但是事务会不能生效;
3.建议将该注解使用在具体的类或者方法上,不要注解在接口上面,因为注解是不能被继承,这样造成编程上会相当麻烦,
注解位置个人看法:注解是在dao层(这里指的是和数据库直接联系的dao层)还是在service层?
从直观的想法来看,我们第一反应应该是在dao层加入,因为这里和数据库直接发生关系,但是只是单个的方法在事务中,eg:addUser(),那在dao层加入事务可以方便控制到,但是如果同时有2个或者更多的方法需要在一个事务中,那就不能方便的控制到,所以个人一般将事务放在service层,可以更好的控制到事务。
@Transactional
publicclass ServiceDaoImpl implements ServiceDao {
private UserDao userDao ;
public UserDao getUserDao() {
returnuserDao;
}
publicvoid setUserDao(UserDao userDao) {
this.userDao = userDao;
}
publicvoid saveUserService() {
// TODO Auto-generated method stub
System.out.println("service.....");
userDao.saveUser();
}
public User getUserService() {
// TODO Auto-generated method stub
User user = userDao.getUser(8);
return user ;
}
}
如果其中某个方法不需要开启事务可以通过如下方式在方法上进行注解:
@Transactional(propagation=Propagation.NOT_SUPPORTED)
publicvoid saveUserService() {
// TODO Auto-generated method stub
System.out.println("service.....");
userDao.saveUser();
}
@Transactional的默认值:
1. 默认的传播事务是:Propagation.REQUIRED
2. 默认的隔离级别:ISOLATION_DEFAULT
3. 事务是读写
4. 任何RuntimeException将触发事务的回滚,但是任何checkedException将不触发事务回滚;
Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是 unchecked,如果遇到checked意外就不回滚;
如何改变默认规则:
a 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)
b 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
c 不需要事务管理的(只查询的)方法:
@Transactional(propagation=Propagation.NOT_SUPPORTED)
5. 事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
属性 | 类型 | 描述 |
传播性 | 枚举型:Propagation | 可选的传播性设置 |
隔离性 | 枚举型:Isolation | 可选的隔离性级别(默认值:ISOLATION_DEFAULT) |
只读性 | 布尔型 | 读写型事务 vs. 只读型事务 |
超时 | int型(以秒为单位) | 事务超时 |
回滚异常类(rollbackFor) | 一组 Class 类的实例,必须是Throwable 的子类 | 一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。 |
回滚异常类名(rollbackForClassname) | 一组 Class 类的名字,必须是Throwable的子类 | 一组异常类名,遇到时 必须 进行回滚 |
不回滚异常类(noRollbackFor) | 一组 Class 类的实例,必须是Throwable 的子类 | 一组异常类,遇到时 必须不 回滚。 |
不回滚异常类名(noRollbackForClassname) | 一组 Class 类的名字,必须是Throwable 的子类 | 一组异常类,遇到时 必须不 回滚 |
事务的传播行为有:
@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
事物超时设置:
@Transactional(timeout=30) // 默认是30秒
事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据