文章目录
10.代理模式
代理模式:是Spring AOP的底层!【SpringAOP 和 SpringMVC】
代理模式分为两种:
-
静态代理
-
动态代理
10.1静态代理1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qxzMWKNO-1598368212221)(C:\Users\Tyrion\AppData\Roaming\Typora\typora-user-images\image-20200810144549036.png)]
角色分析:
- 抽象角色:一般使用接口或抽象类
- 真实角色:被代理的角色
- 代理角色:代理真实角色,之后,一般会做一些附属操作
- 客户:访问代理对象的人
代码部分:
1.接口
package com.tyrion.demo1;
//租房接口
public interface Rent {
public void rent();
}
2.真实角色
package com.tyrion.demo1;
//房东
public class Host implements Rent{
public void rent() {
System.out.println("房东出租房子");
}
}
3.代理角色
package com.tyrion.demo1;
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent(){
check();
host.rent();
sign();
fee();
}
//看房
public void check(){
System.out.println("中介带人看房");
}
//收中介费
public void fee(){
System.out.println("中介收中介费");
}
//签合同
public void sign(){
System.out.println("中介签合同");
}
}
4.客户端访问代理角色
package com.tyrion.demo1;
public class client {
public static void main(String[] args) {
//房东出租房房子
Host host = new Host();
//使用代理,中介帮房东出租
//但是,代理角色一般会有一些附属操作(否则,这样没有意义)
Proxy proxy=new Proxy(host);
//不用面对房东,找中介即可
proxy.rent();
}
}
代理模式的好处
- 可以使真实角色更加纯粹,不用去关注一些公共的业务
- 公共业务交给代理角色,实现业务的分工
- 公共业务扩展时,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率变低
10.2 静态代理2
对于一个实现增删改查的实体类,现在需要增加一个日志功能,为了不改变愿有代码,现在增加一个代理类,在其中实现日志功能
1.接口
package com.tyrion.demo2;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
2.接口实现类
package com.tyrion.demo2;
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void query() {
System.out.println("查询用户");
}
}
3.代理角色
package com.tyrion.demo2;
public class UserServiceProxy {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add(){
log("add");
userService.add();
}
public void delete(){
log("delete");
userService.delete();
}
public void update(){
log("update");
userService.update();
}
public void query(){
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("[Debug] 使用了"+msg+"方法");
}
}
4.客户端
package com.tyrion.demo2;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService=new UserServiceImpl();
UserServiceProxy proxy=new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
10.2 动态代理
- 动态代理和静态代理角色一样
- 动态代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK的动态代理【我们在这里使用】
- 基于类:cglib
- Java字节码实现:JAVAssist
需要了解两个类:Proxy(代理),InvacationHandler(调用处理)
Proxy:提供创建动态代理类和实例的静态方法,它也是这些方法创建的所有动态代理类的超类
InvacationHandler:是由代理实例的调用程序实现的接口。每个代理实例都有一个关联的调用处理程序,当在代理实例上调方法时,方法调用将被编码并分派到调用处理程序的invoke方法
动态代理的好处:
- 所有静态代理的好处都有
- 一个动态代理类代理的是一个接口,一般对应的是一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
代码实现:使用动态代理去实现静态代理2中的增删改查,并实现日志功能
1.代理实现类
package com.tyrion.demo4;
import com.tyrion.demo3.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//我们会用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//1.被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//2.生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//3.处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过反射获取执行的方法
log(method.getName());
//动态代理的本质,就是使用反射机制实现!
Object result=method.invoke(target,args);
return result;
}
//日志功能
public void log(String msg){
System.out.println("[Debug]执行了"+msg+"方法");
}
}
2.客户端
package com.tyrion.demo4;
import com.tyrion.demo2.UserService;
import com.tyrion.demo2.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService=new UserServiceImpl();
//代理角色,现在不存在
ProxyInvocationHandler handler=new ProxyInvocationHandler();
//1.设置要代理的对象
handler.setTarget(userService);
//动态生成代理类
UserService proxy=(UserService) handler.getProxy();
proxy.query();
}
}
11. AOP
11.1 什么是AOP
AO(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
11.2 AOP在Spring中的作用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wsj5mt2C-1598368212225)(C:\Users\Tyrion\AppData\Roaming\Typora\typora-user-images\image-20200811115510619.png)]
提供声明式事务,允许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即,与我们业务逻辑无关的但是我们需要关注的部分,如,日志,安全,缓存,事务等等
切面(Aspect):横切关注点 被模块化的 特殊对象,是一个类【例如我们的Log】
通知(Advice):切面必须要完成的工作,是类中方法【Log中的方法】
目标(Target):被通知对象【我们代理中使用的target】
代理(Proxy):向目标对象应用通知会后创建的对象【生成的代理类】
切入点(PointCut):切面通知执行的“地点”定义
连接点(JointPoint):与切入点匹配的执行点
SpringAOP中,通过Advice定义横切逻辑,Spring支持5种类型的Advice
通知类型 | 连接点 | 实现接口 |
---|---|---|
前置通知 | 方法前 | org.springframework.aop.MethodBeforeAdvice |
后置通知 | 方法后 | org.springframework.aop.AfterReturningAdvice |
环绕通知 | 方法前后 | org.aopalliance.intercept.MethodInterceptor |
异常抛出通知 | 方法抛出异常 | org.springframework.aop.ThrowsAdvice |
引介通知 | 类中增加新的方法属性 | org.springframework.aop.IntroductionInterceptor |
即AOP在不改变原有代码的情况下,去增加新的功能
11.3 使用Spring实现AOP
需要导入一个依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
方式一:使用Spring的API接口
1.接口
package com.tyrion.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
2.接口实现类
package com.tyrion.service;
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void select() {
System.out.println("查询用户");
}
}
3.日志功能:before
package com.tyrion.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//objects:参数
//o:目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
4.日志功能:after
package com.tyrion.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
@Override
public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
}
}
5.xml配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.tyrion.service.UserServiceImpl"/>
<bean id="log" class="com.tyrion.log.Log"/>
<bean id="afterLog" class="com.tyrion.log.AfterLog"/>
<!-- 方式一:使用原生API-->
<!-- 配置AOP-->
<aop:config>
<!-- 切入点 expression:表达式,execution(要执行的位置 *****)-->
<aop:pointcut id="pointcut" expression="execution(* com.tyrion.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
来自B站评论区:
execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))注意老师忽略掉修饰符了 自己可以写上修饰符试试
(…)可以代表所有参数,()代表一个参数,(,String)代表第一个参数为任何值,第二个参数为String类型.
PS:execution表达式是最常用的切点函数,语法如下:
1.execution():表达式主体
2.第一个*:表示返回类型,*代表所有类型
3.包名:表示需要拦截的包,com.tyrion.service.UserServiceImpl.*表示这个类下的所有方法
4.(…):表示方法的参数,两个句点表示任何参数
6.测试类
import com.tyrion.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的是接口,返回值一定要写成接口,不能写实现类
UserService userService=context.getBean("userService", UserService.class);
userService.delete();
}
}
方式二:自定义实现AOP【主要是切面定义】
1.自定义日志类
package com.tyrion.diy;
public class diyPointCut {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
2.xml文件配置
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.tyrion.service.UserServiceImpl"/>
<bean id="log" class="com.tyrion.log.Log"/>
<bean id="afterLog" class="com.tyrion.log.AfterLog"/>
<!-- 方式二:自定义类-->
<bean id="diy" class="com.tyrion.diy.diyPointCut"/>
<aop:config>
<!-- 自定义切面,ref是要引用的类-->
<aop:aspect ref="diy">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.tyrion.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
3.方式三:使用注解实现
xml配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.tyrion.service.UserServiceImpl"/>
<bean id="log" class="com.tyrion.log.Log"/>
<bean id="afterLog" class="com.tyrion.log.AfterLog"/>
<!-- 方式三-->
<bean id="annotationPointCut" class="com.tyrion.diy.AnnotationPointCut"/>
<!--开启注解支持 JDK实现:proxy-target-class="false"(默认) cglib实现:proxy-target-class="true"-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>
自定义类
package com.tyrion.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.tyrion.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.tyrion.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取切入的点
@Around("execution(* com.tyrion.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jointpoint) throws Throwable{
System.out.println("环绕前");
System.out.println("获取签名:"+jointpoint.getSignature());
//执行方法
Object proceed=jointpoint.proceed();
System.out.println("环绕后");
}
}
测试类执行结果:
环绕前
获取签名:void com.tyrion.service.UserService.delete()
方法执行前
删除用户
环绕后
方法执行后
12. 整合Mybatis
步骤:
1.导入相关jar包
-
junit
-
mybatis
-
mysql
-
Spring相关
-
aop植入
-
mybatis-spring【新的】
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2编写配置文件
3.测试
12.1 mybatis
1.编写实体类
package com.tyrion.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
2.编写核心配置文件
<?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核心配置文件-->
<configuration>
<typeAliases>
<package name="com.tyrion.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode-true&characterEncoding=UTF-8&serverTimezone=UTC&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 每一个Mappers.xml都需要在Mybatis核心文件中注册-->
<mappers>
<mapper class="com.tyrion.mapper.UserMapper"/>
</mappers>
</configuration>
3.编写接口
package com.tyrion.mapper;
import com.tyrion.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
4.编写Mapper.xml
<?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.tyrion.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from mybatis.user
</select>
</mapper>
5.测试
import com.tyrion.mapper.UserMapper;
import com.tyrion.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Mytest {
@Test
public void Test() throws IOException {
String resource = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUser();
for (User user : userList) {
System.out.println(user);
}
}
}
PS:maven存在静态资源过滤的问题,需要在pom文件中进行配置
<!-- 在build中配置resources,防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
12.2Mybatis-Spring——1
官网: http://mybatis.org/spring/zh/index.html
-
配置文件
- 编写数据源配置
- SqlSessionFactory
- SqlSessionTemplate
spring-dao.xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode-true&characterEncoding=UTF-8&serverTimezone=UTC&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSession-->
<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:com/tyrion/mapper/*.xml"/>
</bean>
<!-- SqlSessionTemplate:就是我们使用的SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能使用构造器注入,它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
由于在Spring中完成了部分原来有mybatis配置文件完成的工作,所以可以对mybatis.xml进行修改(事实上,所有工作都可以由Spring配置文件完成,但老师建议保留mybatis.xml)
<?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核心配置文件-->
<configuration>
<typeAliases>
<package name="com.tyrion.pojo"/>
</typeAliases>
</configuration>
在applicationContext.xml中注册userMapper,并引入dao.xml(实际上可以写到一起,这样做是为了明确文件的分工,且spring.xml文件几乎不用再做修改)
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.tyrion.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
- 需要给接口加实现类
package com.tyrion.mapper;
import com.tyrion.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
//原来我们的所有操作,都使用SqlSession来执行,
//现在,我们使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
- 将实现类注入到Spring中,进行测试
import com.tyrion.mapper.UserMapper;
import com.tyrion.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
@Test
public void Test() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = applicationContext.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
12.2Mybatis-Spring——2
除上述方式外,新版本的Mybatis-Spring还有一种实现方式,相比之下更加简洁
我们写一个userMapperImpl2.java实现接口,其中我们继承SqlSessionDaoSupport,这样可以直接使用getSqlSession()方法获取SqlSession
package com.tyrion.mapper;
import com.tyrion.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
这样,我们无需之前的setTemplate方法,因此,在xml文件中也可以进行简化,删除sqlSessionTemplate的bean注册
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode-true&characterEncoding=UTF-8&serverTimezone=UTC&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSession-->
<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:com/tyrion/mapper/*.xml"/>
</bean>
</beans>
13.声明式事务
13.1回顾事务
- 要么都成功,要么都失败
- 事务在项目开发中十分重要,涉及到数据的一致性问题
- 确保完整性和一致性
事务的ACID原则:
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中
13.2Spring中的事务管理
- 声明式事务:AOP
- 编程式事务:需要写代码,进行事务的管理
在spring-dao.xml中进行配置
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode-true&characterEncoding=UTF-8&serverTimezone=UTC&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSession-->
<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:com/tyrion/mapper/*.xml"/>
</bean>
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 结合AOP实现事务的植入-->
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务-->
<!-- 配置事务的传播特性: propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.tyrion.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
在spring-dao.xml中进行配置
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode-true&characterEncoding=UTF-8&serverTimezone=UTC&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSession-->
<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:com/tyrion/mapper/*.xml"/>
</bean>
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 结合AOP实现事务的植入-->
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务-->
<!-- 配置事务的传播特性: propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.tyrion.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>