声明式事务
回顾事务
- 把一组业务当成一个业务来做;要么都成功,要么都失败
- 事务在项目开发中,十分重要,设计到数据的一致性问题,不能马虎
- 确保完整性和一致性;
事务ACID原则: - 原子性:事务是最小的单元,这个事务要么失败不起作用,要么就是完成,只有这两种情况。
- 一致性:事务完成或失败必须保证事务所操作的说有数据都保持一样操作,要么所有数据都操作成功,要么都操作失败,不存在一部分数据操作成功,一部分数据操作失败。
- 隔离性:并发事务中,一个事务的操作不影响其他事务完成状态。对里面的数据影响需要事务的隔离级别来控制隔离性。
- 持久性:一旦事务完成,对数据库的操作是持久性的。
Spring声明式事务配置
编写接口
public interface UserMapper {
public List<Use> selectUser();
public int addUser(Use use);
public int deleteUser(int id);
}
如果我在这里写错了删除的sql语句的话
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wx.mapper.UserMapper">
<select id="selectUser" resultType="com.wx.pojo.Use">
select * from user
</select>
<insert id="addUser" parameterType="com.wx.pojo.Use">
insert into user (id,name,pwd) value (#{id},#{name},#{pwd});
</insert>
<delete id="deleteUser" parameterType="int">
deletes from user where id = #{id}
</delete>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--DataSource:使用Spring的数据源替换Mybatis的配置
这里使用Spring的jdbc-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定Mybatis配置文件-->
<property name="mapperLocations" value="com/wx/mapper/*.xml"/>
</bean>
<bean id="userMapper" class="com.wx.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
package com.wx.mapper;
import com.wx.pojo.Use;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public int addUser(Use use) {
return getSqlSession().getMapper(UserMapper.class).addUser(use);
}
@Override
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
@Override
public List<Use> selectUser() {
Use use = new Use (8,"小王","111");
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.addUser(use);
mapper.deleteUser(8);
return mapper.selectUser();
}
}
然后在这里调用增加和删除的方法
然后测试
import com.wx.mapper.UserMapper;
import com.wx.mapper.UserMapperImpl;
import com.wx.pojo.Use;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (Use use : userMapper.selectUser()) {
System.out.println(use);
}
}
}
就可以发现添加了这个id为8的,但因为删除的sql写错了他并没有删除,但事实上这里因为出错也不应该将其添加成功,如果这个是金钱交易的话,这边打入款了,但另一边并没有入款,所以我们要使用事务。
在spring中配置声明事务
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
我们还要导入头文件约束
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
然后结合AOP实现事务的织入
<!--结合AOP实现事务的织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性: new propagation = -->
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="delete*"/>
<tx:method name="select*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.wx.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
tx:method 属性
name:与事务属性关联的方法名。通配符()可以用来指定一批关联到相同的事务属性的方法。 如:'get’、‘handle*’、'on*Event’等等。
propagation:事务传播行为,可选的有:
- REQUIRED:指定当前方法必需在事务环境中运行,如果当前有事务环境就加入当前正在执行的事务环境,如果当前没有事务,就新建一个事务。这是默认值。
- SUPPORTS:指定当前方法加入当前事务环境,如果当前没有事务,就以非事务方式执行。
- MANDATORY:指定当前方法必须加入当前事务环境,如果当前没有事务,就抛出异常。
- REQUIRES_NEW:指定当前方法总是会为自己发起一个新的事务,如果发现当前方法已运行在一个事务中,则原有事务被挂起,我自己创建一个属于自己的事务,直我自己这个方法commit结束,原先的事务才会恢复执行。
- NOT_SUPPORTED:指定当前方法以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,等我以非事务的状态运行完,再继续原来的事务。
- NEVER:指定当前方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常,只有没关联到事务,才正常执行。
- NESTED:指定当前方法执行时,如果已经有一个事务存在,则运行在这个嵌套的事务中.如果当前环境没有运行的事务,就新建一个事务,并与父事务相互独立,这个事务拥有多个可以回滚的保证点。就是指我自己内部事务回滚不会对外部事务造成影响,只对DataSourceTransactionManager事务管理器起效。
然后再次删除数据库中id为8的,再次运行
可以发现就不会添加成功