Maven项目&Spring+Mybatis AOP织入事务
事务:就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
事务四个属性ACID
原子性(atomicity)
事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
一致性(consistency)
一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
隔离性(isolation)
可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
持久性(durability)
事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
使用 Maven 作为构建工具,整合Spring、Mybatis,代码实现
实体类
package com.sc.pojo;
import lombok.Data;
@Data
public class Member {
private Long id;
private String memberNo;
private String mobile;
private String openId;
private Shop shop;
}
package com.sc.pojo;
import lombok.Data;
@Data
public class Shop {
private int shopInfoId;
private String shopName;
private String appKey;
private String appSecret;
private Long shopId;
private String shopCode;
private String saasTenantCode;
}
业务接口:
package com.sc.service;
import com.sc.pojo.Member;
import java.util.List;
public interface MemberMapper {
int deleteMember(Long id);
int addMember(Member member);
}
接口实现类
package com.sc.service;
import com.sc.pojo.Member;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class MemberMapperImpl implements MemberMapper {
//sqlSession不用我们自己创建了,Spring来管理
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public int deleteMember(Long id) {
MemberMapper mapper = sqlSession.getMapper(MemberMapper.class);
Member tdyMemberInfo = new Member();
tdyMemberInfo.setMemberNo("20211209100001132");
tdyMemberInfo.setMobile("18660461132");
tdyMemberInfo.setOpenId("PDH2JKKE3JUKAG6M7V12332");
mapper.addMember(tdyMemberInfo);
return mapper.deleteMember(id);
}
@Override
public int addMember(Member member) {
MemberMapper mapper = sqlSession.getMapper(MemberMapper.class);
return mapper.addMember(member);
}
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sc.service.MemberMapper">
<resultMap id="memberResultMap" type="Member">
<result property="id" column="member_id"/>
<result property="memberNo" column="member_no"/>
<result property="mobile" column="mobile"/>
<result property="openId" column="open_id"/>
<!--关联对象property 关联对象在TdyShop实体类中的属性-->
<association property="shop" javaType="Shop">
<result property="shopInfoId" column="shop_info_id"/>
<result property="shopId" column="shop_id"/>
<result property="shopName" column="shop_name"/>
<result property="appKey" column="app_key"/>
<result property="appSecret" column="app_secret"/>
<result property="shopCode" column="shop_code"/>
<result property="saasTenantCode" column="saas_tenant_code"/>
</association>
</resultMap>
<delete id="deleteMember" parameterType="long" >
deleted from t_dy_member_info where member_id=#{id}
</delete>
<insert id="addMember" parameterType="Member">
INSERT INTO t_dy_member_info
(shop_id,member_code,member_no,mobile,mix_mobile,open_id,`level`,bind_status,bind_status_time,`point`,point_time,create_time,last_modify_time)
VALUES (9730231,NULL,#{memberNo},#{mobile},NULL,#{openId},1,1,NULL,0,NULL,NULL,NULL)
</insert>
</mapper>
上述mapper文件中, 故意把 delete 写成deleted。
数据库配置信息db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://XXXX:3306/dXXX_sit?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useJDBCCompliantTimezoneShift=true&serverTimezone=CST
jdbc.username=XXX
jdbc.password=XXX
Mybatis配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases >
<package name="com.sc.pojo"/>
</typeAliases>
</configuration>
spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--关联Mybatis-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--利用构造器注入-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="memberMapper" class="com.sc.service.MemberMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
<!--JDBC事务管理器-->
<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="*" propagation="REQUIRED"/>
<tx:method name="addMember" propagation="REQUIRED"/>
<tx:method name="deleteMember" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.sc.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
测试类
@Test
public void test2()
{
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
MemberMapper mapper = (MemberMapper) context.getBean("memberMapper");
int code2 = mapper.deleteMember(new Long(489));
if(code2>0){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
}
如果mapper文件正确配置,结果就是 插入成功,删除失败。
因为mapper文件中,delete写成了deleted,所以执行结果,报错。发现插入失败,删除失败。
上述可以看出,Spring为我们提供了事务管理,只需要配置即可。
这里使用的是声明式事务管理:
1)将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
2)将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
使用Spring管理事务,注意头文件的约束导入 : tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
JDBC事务
<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="*" propagation="REQUIRED"/>
<!-- <tx:method name="addMember" propagation="REQUIRED"/>-->
<!-- <tx:method name="deleteMember" propagation="REQUIRED"/>-->
</tx:attributes>
</tx:advice>
spring配置文件中配置AOP
导入aop的头文件
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.sc.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
以上即完成了AOP织入事务的全部过程。