public int addAdmin(AdminInfo admin) {
String sql="insert into adminInfo (adminName,password,note) values (?,?,?)" ;
int result=t.update(sql,admin.getAdminName(),admin.getPassword(),admin.getNote());
int a=9/0;
return result;
}
上例中的方法默认是没有事务管理的,比如上面的程序,虽然方法执行的过程中出错了,但数据还是添到数据库中了,显然,这是有问题的,这时候我们就要用到事务管理了,使得整个方法要么全成,要么不成
一、传统的jdbc中如何进行事务管理
1、在操作之前开启事务管理conn.setAutoCommit(false)
2、在操作之后提交事务conn.commit();
3、出现异常的时候进行事务回滚,默认情况下,会自动回滚
4、如果想手动回滚,可以在catch块中写conn.rollback()
static vois teat(){
Connection conn=null;
PreparedStatement stm=null;
try{
conn=DBUtil.getConnection();
conn.setAutocommit(false);//开启事务
String sql="update userinfo set money=money-500 where id=9";//给id为9的用户扣500元
stm=conn.preparedStatement(sql);
stm.executeUPdate();
String sql2="update userinfo set money=money+500 where id=10";//给id为10的用户加500元
conn.commit();//提交事务
}catch(Exception ex){
ex.printStackTrace();
}finally{
DBUtil.close(null,stm,conn);
}
}
如果上面的程序用户id为9的扣了500,结果用户id为10 的没收到500,那岂不是出了大事
//下面的程序,在传统的jdbc里实现事务比较困难,原因是两个方法用的是不同的connection对象
static void 转账(){
扣钱();
加钱();
}
static void 扣钱(){
connection conn...
}
static void 加钱(){
connection conn...
}
二、spring中,进行事务管理(也属于AOP编程的一部分),主要有两种方式
1)注解方式
2)xml配置的方式 //较好
1)注解方式
(1)引入tx名称空间
(2)配置一个事务管理器
<bean name="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="datasource"/>
</bean>
(3)声明要用注解管理事务
<tx:annotation-driven transaction-manager="txManager"/>
(4)在要进行书屋管理的类中的方法上加注解@Transactional表示要开启事务管理
2)xml配置文件的方式
<!-- 设置一个事务的切入点 -->
<aop:config>
<aop:pointcut expression="execution(* com.dao.UserDaoImpl.*(..))" id="txpointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txpointCut"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 除了get打头的方法我不需要事务,其他的采取默认的 -->
<tx:attributes>
<tx:method name="get*" propagation="NOT_SUPPORTED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
三、关于@Transactional注解
1、也可以加在类体上:加在类体上,则类中的所有方法都受他的控制
2、可以指定事务的传播行为
@Transactional(propagation = Propagation.REQUIRED) //默认
@Transactional(propagation = Propagation.NoSupport) //不支持事务
四、事务的传播行为
----REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么
加入到该事务,否则为自己创建一个新的事务。
//例
@Transactional(propagation = Propagation.REQUIRED)
public void testTx() {
t.update("delete from adminInfo where id=92");//语句1
delAdmin(90);//语句2
t.update("delete from adminInfo where id=93");//语句3
int x=9/0;//此处执行出现异常,上面的操作全部没用,通通回退
}
@Transactional(propagation = Propagation.REQUIRED)注解
执行到语句1的时候发现没有事务,自己创建一个事务
执行到语句2的时候,发现自己已经处于一个事务中(语句1开启的事务),则加入该事物
语句3和语句2一样
----NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开 启事务
如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后 原先的事务便会恢复执行。(意思就是即使方法出了错,我做过的操
作还是会保留的,不会回退)
----MANDATORY (mandatory,强制的,命令的,受委托的):该属性指定业务方法只能在一个已经存
在的事务中执行,业务方法不能发起自己的事务。
如果业务方法在没有事务的环境下调用,容器就会抛出例外。
----SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,
则方法成为该事务的一部分。如果业务方法在事务范围外被调用,
则方法在没有事务的环境下执行。
----Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,
容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。 ----NESTED:nested (窝,嵌套)如果一个活动的事务存在,则运行在一个嵌套的事务中.
如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的 事务, 这个事务拥有多个可以回滚的保存点。
内部事务的回滚不会对外部事务造成影响。它只对 DataSourceTransactionManager事务管理器起效