一、学习目标
声明式事务是Spring框架提供的一种事务管理方式,其主要特点是通过声明(而非编程)的方式来处理事务。这种方式让事务管理不侵入业务逻辑代码,从而提高了代码的可维护性和可读性。
定义:声明式事务通过配置文件或注解的方式在Spring中声明事务的边界和事务的属性,而不是在代码中显式地编写事务管理逻辑。
特点:
非侵入性:事务管理不侵入业务逻辑代码,业务逻辑对象无需知道自己正在被事务管理。
灵活性:事务管理策略可以在配置文件中灵活修改,无需修改业务代码。
易于维护:当需要修改事务管理策略时,只需在配置文件中进行修改,无需重新编译代码。
二、
以上一篇博客day7为例:
1.接口
public interface UserMapper {
public List<User> selectUser();
//添加一个用户
int addUser(User user);
//根据id删除用户
int deleteUser(int id);
void testUser();
}
2.在UserMapper.xml添加并故意添加错误(deletete)
<insert id="addUser" parameterType="com.lzh.pojo.User">
insert into users (id,name,age) values (#{id},#{name},#{age})
</insert>
<delete id="deleteUser" parameterType="int">
deletete from users where id = #{id}
</delete>
3.修改接口实现类
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectUser();
}
public int addUser(User user) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.addUser(user);
}
//删除
public int deleteUser(int id) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.deleteUser(id);
}
@Override
public void testUser() {
User user = new User(4,"李四",30);
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(4);
}
}
4.测试
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserMapper mapper = (UserMapper) context.getBean("userDao");
mapper.testUser();
List<User> user = mapper.selectUser();
System.out.println(user);
}
添加之前的测试结果
测试后,因为故意添加了错误,所以会爆红
但是,结果由原来的三个用户增加到了四个,这是因为虽然delete出错,但Insert插入成功,所以添加了一个用户,这样显然不利于我们的开发,因此,我们接下来要学习声明式事务。
三、
1.导入约束
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置数据源->
定义一个数据源bean,id为"dataSource",用于管理数据库连接。
class属性指定了数据源的实现类为org.springframework.jdbc.datasource.DriverManagerDataSource,
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--
设置数据库连接的URL。
- useSSL=true&useSSL=false:这里似乎有一个错误,通常只需要一个useSSL参数,并且应该保持一致。
对于本地开发,通常不需要SSL,所以应设置为false。
- useUnicode=true:指定使用Unicode字符集。
- characterEncoding=utf8:指定字符编码为UTF-8。注意,从MySQL 5.5.3版本开始,建议使用utf8mb4代替utf8,
以支持更广泛的Unicode字符,包括emoji表情等。
-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="admin123"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据源,这里的ref指向之前定义的数据源bean -->
<property name="dataSource" ref="dataSource"/>
<!-- 关联Mybatis的全局配置文件,MybatisConfig.xml中包含了MyBatis的设置,如别名、类型处理器、插件等 -->
<property name="configLocation" value="classpath:MybatisConfig.xml"/>
<!-- 指定Mapper XML文件的位置,MyBatis会根据这些XML文件来创建Mapper接口的实现 -->
<!-- 注意:这里只指定了一个Mapper XML文件,如果有多个,可以使用逗号分隔或者使用通配符 -->
<property name="mapperLocations" value="classpath:com/lzh/dao/UserMapper.xml"/>
</bean>
<!-- 注册sqlSessionTemplate,关联sqlSessionFactory -->
<!--bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
< 通过构造器注入SqlSessionFactory,使得SqlSessionTemplate能够管理SqlSession -->
<!-- index="0"指定了构造器参数的索引,这里假设SqlSessionTemplate的构造器第一个参数就是SqlSessionFactory -->
<!--constructor-arg index="0" ref="sqlSessionFactory"/>
</bean-->
<!--bean id="userDao" class="com.lzh.dao.UserDaoImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean-->
<bean id="userDao" class="com.lzh.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.lzh.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
2.事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
3.配置事务通知
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
4.配置AOP
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.lzh.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
5.测试
在删除了第四个用户后,测试发现虽然依旧爆红,但并没有增加第四个用户。