Spring的使用(入门到熟练)—强势总结
Spring:春天 ==》寓意就是程序员的春天来了
这里抛一个问题 在一个项目中如何使用多个框架呢? 又怎么将多个框组合到一起?
Spring这个框架最大的功能就是能够为业务逻辑层
提供事务
整合第三方框架
他相当于是所有框架之间的粘合剂。也就是说,这个鬼就像我们的胶水一样,能够把其他的框架整合到一起
1、Spring能干什么
- 为业务逻辑层提供事务
- 整合第三方框架
- 为Controller提供解决方案
- 为DAO层提供解决方案
- 提供了AOP编程的这种思想
- 实现了对象依赖的解耦
2、Spring中的七大模块
Core
:这个是Spring的核心模块 主要功能 IOC(控制反转) DI(依赖注入)AOP
:面向切面编程 就是将你以前的重复代码,抽取城一个类,然后原来程序在正常运行的时候 动态植入我们抽取出来的代码,的这种编程思想就叫做面向切面编程Web MVC
:这个模块就是传说中的 SpringMVC,也就说SpringMVC其实是Spring框架的一个模块哦,别搞错了Web
:Spring这个框架对Web开发的支持Context
:上下文模块(这个就是类似一个类,这个类中保存了程序运行的所有信息,通过这个类就可以找到我们程序运行过程中的所有数据)DAO
:Spring提供了对数据库访问的支持,也就是JdbcTemplate(这个鬼类似于DBUtils的使用)ORM
:(Object Relation Mapping) 对象关系映射 即Java对象通过映射关系,映射到数据库表中,也就是表字段与属性一一对应,这里补充一下,Spring整合第三方数据库访问框架有 (Hibernate Mybatis Toplink …)
3、Spring的第一个程序
- 创建一个maven工程,这里是通过idea创建的
- pom.xml 导包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--导入Spring的相关包-->
<!--core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--web mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
- 创建User类
package com.csdn.pojo;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private void init() {
System.out.println("执行了初始化方法");
}
private void destory() {
System.out.println("执行了销毁方法");
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password=" + password +
'}';
}
}
- 创建spring配置文件
spring的配置文件名称是可以任意命名的,一般情况命名为spring.xml
或者 spring-config.xml
这里是最齐全的spring-config.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--创建类的对象
这个Spring创建完对象之后 会放到一个容器中
这个容器 就叫做 IOC容器 或者 单例池
id:给这个对象整一个唯一的标识
name:给生成的对象弄个名字
class:要生成那个类的对象
scope:这个表示的是生成对象是单例还是多例呢?
singleton:表示生成的是单例(单例会放到容器中)
prototype:这个表示的是生成这个对象是多例的(是不会放到容器中的)
init-method:当我们的对象放到IOC容器去之后 如果要进行初始化的操作 那么就调用这个后面的方法
destroy-method:当这个对象在IOC容器中要进行销毁的时候 要执行的方法
-->
<bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false"></bean>
</beans>
- 接下来测试一波
public class TestUser {
@Test
public void testUser(){
//classpath:表示resource文件夹的路径
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
//通过name获取bean
User user = (User)context.getBean("user");2
System.out.println("拿到的这个对象是:" +user);
context.close();
}
}
测试结果
4、Spring IOC
IOC
:控制反转
相信部分小伙伴都会有这个疑问 谁控制了谁? 什么东西反转了?
接下来说说Java创建对象的方式有哪些 new 反射 序列化 克隆
IOC这个概念: 谁控制了谁? 原来闯将对象是程序员自己来完成的 学习了Spring之后,我们对象的创建就交给Spring来完成
即Spring控制了Java对象的这个创建
什么东西反转了呢? 创建对象的权力反转了,原来由程序员自己完成 现在由Spring来完成
4.1通过配置文件创建对象
4.1.1创建简单对象
<!--创建类的对象
这个Spring创建完对象之后 会放到一个容器中
这个容器 就叫做 IOC容器 或者 单例池
id:给这个对象整一个唯一的标识
name:给生成的对象弄个名字
class:要生成那个类的对象
scope:这个表示的是生成对象是单例还是多例呢?
singleton:表示生成的是单例(单例会放到容器中)
prototype:这个表示的是生成这个对象是多例的(是不会放到容器中的)
init-method:当我们的对象放到IOC容器去之后 如果要进行初始化的操作 那么就调用这个后面的方法
destroy-method:当这个对象在IOC容器中要进行销毁的时候 要执行的方法
-->
<bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false">
</bean>
4.1.2创建有构造器的对象
<!--创建一个带有构造器的对象 通过下标来构建我们的这个数据-->
<bean id="user" class="com.csdn.pojo.User">
<constructor-arg index="0" value="叽莫叽"></constructor-arg>
<constructor-arg index="1" value="123"></constructor-arg>
</bean>
<!--通过变量名字来初始化我们的对象-->
<bean id="user2" class="com.csdn.pojo.User">
<constructor-arg name="password" value="123"></constructor-arg>
<constructor-arg name="username" value="叽莫叽"></constructor-arg>
</bean>
4.2静态工厂创建对象
package com.csdn.factory;
import com.csdn.pojo.User;
/**
* 工厂创建user
* @author jimoji
* @date : 2022-11-19
*/
public class UserFactory {
/**
* 非静态工厂创建对象
* @return
*/
public User getUser(){
return new User("非静态工厂创建对象1","11111111111");
}
/**
* 静态方法创建对象
* @return
*/
public static User getStaticUser(){
return new User("静态工厂创建对象2","11111111111");
}
}
编写我们的spring-config.xml
<!--静态工厂创建对象-->
<bean id="user3" class="com.csdn.factory.UserFactory" factory-method="getStaticUser"></bean>
<!--非静态工厂创建对象-->
<bean id="userFactory" class="com.csdn.factory.UserFactory"></bean>
<!--
factory-bean:这个表示的是工厂实例 这个实例一定要放到IOC容器
factory-bean后面的值 一定是我们容器中对象的这个名字或者id
-->
<bean id="user4" factory-bean="userFactory" factory-method="getUser"></bean>
5、Spring DI
DI:依赖注入
谁依赖谁?
回顾一下三层结构 Controller —》Service —》DAO —》DB
你暂时可以这样去认为:
Controller依赖于Service
Serivce依赖于DAO
DAO依赖于DB
即一个类中,维护了另外一个类的实例对象 那么我们就可以认为 维护的这个类 依赖于被维护的这个类
注入了什么东西?
注入的是类的实例对象,还可以是具体的值,简单的说 啥都可以注入
注入:说白了就是给成员变量赋值 而这个值必须要在IOC容器中,如我们现在已经在xml文件中配置的user user1…都可以被
创建一个UserService
public class UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void print(){
userDAO.print();
}
}
5.1 Set注入
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService">
<!--Set注入的前提是这个成员变量一定要有Set方法
在这种注入数据的方式在开发中用的很多
ref:这一个表示的是引用 从IOC容器中去找对象 找对象的时候这个ref的值实际上就是我们对象在IOC容器中的这个值
value:表示给定一个具体的值
-->
<!--这里的
第一个userDAO是UserService类中set方法的名字
第二个userDAO是xml文件中id=userDAO的bean
-->
<property name="userDAO" ref="userDAO"></property>
</bean>
5.2 p标签注入
注意事项:就是我们的成员变量也必须要写 Set方法
还需要在beans引入 xmlns:p=“http://www.springframework.org/schema/p” 否则没法玩
说明一个问题:p标签注入的底层也是 set注入
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService" p:userDAO-ref="userDAO"></bean>
5.3 内部bean注入
<!--第三种注入方式:内部bean注入
前提是类必须要为成员变量写Set方法
这种方式的底层也是Set注入
-->
<bean id="userService" class="com.csdn.di.UserService">
<property name="userDAO">
<bean class="com.csdn.di.UserDAO"></bean>
</property>
</bean>
5.4 构造器注入
<!--下面写个构造器注入 说白了 就是在构造器上 为成员变量赋值-->
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService">
<constructor-arg name="userDAO" ref="userDAO"></constructor-arg>
</bean>
6、自动装配
autowire=“byName”:表示的意思是 会去找UserService中拥有Set方法的成员变量 然后通过名字去
IOC容器中找 名字相同的对象然后实施赋值
即UserService若有UserDAO这个属性,就会通过userDAO的set方法去容器中找userDAO的bean
<!--下面玩的是自动装配-->
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<!--
autowire="byType" :这个表示的是通过类型 去IOC容器中找类型和 成员变量相同的然后实施赋值
注意:成员变量必须有Set方法
-->
<bean id="userService" class="com.csdn.di.UserService" autowire="byType"></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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--创建User类的对象-->
<bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false"></bean>
<!--创建一个带有构造器的对象 通过下标来构建我们的这个数据-->
<bean id="user" class="com.csdn.pojo.User">
<constructor-arg index="0" value="叽莫叽"></constructor-arg>
<constructor-arg index="1" value="123"></constructor-arg>
</bean>
<!--通过变量名字来初始化我们的对象-->
<bean id="user2" class="com.csdn.pojo.User">
<constructor-arg name="password" value="123"></constructor-arg>
<constructor-arg name="username" value="叽莫叽"></constructor-arg>
</bean>
<!--静态工厂创建对象-->
<bean id="user3" class="com.csdn.factory.UserFactory" factory-method="getStaticUser"></bean>
<!--非静态工厂创建对象-->
<bean id="userFactory" class="com.csdn.factory.UserFactory"></bean>
<bean id="user4" factory-bean="userFactory" factory-method="getUser"></bean>
<!--第一种注入方式:Set注入-->
<bean id="userDAO1" class="com.csdn.di.UserDAO"></bean>
<bean id="userService1" class="com.csdn.di.UserService">
<property name="userDAO" ref="userDAO1"></property>
</bean>
<!--第一种注入方式:p标签注入-->
<bean id="userDAO2" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService" p:userDAO-ref="userDAO2"></bean>
<!--第三种注入方式:内部bean注入-->
<bean id="userService3" class="com.csdn.di.UserService">
<property name="userDAO">
<bean class="com.csdn.di.UserDAO"></bean>
</property>
</bean>
<!--第四种注入方式:构造器注入-->
<bean id="userDAO4" class="com.csdn.di.UserDAO"></bean>
<bean id="userService4" class="com.csdn.di.UserService">
<constructor-arg name="userDAO" ref="userDAO4"></constructor-arg>
</bean>
<!--下面玩的是自动装配-->
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService" autowire="byType"></bean>
</beans>
7、使用注解完成上述功能
7.1 Spring的原始注解主要是替代<Bean>
的配置
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在Service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
注意:@Controller
、@Service
、@Repository
实际上只是为了我们更方便阅读,被语义化的注解,其实作用更@Component
一样
//<bean name="userDao" class="com.dao.impl.UserDaoImpl"></bean>
//使用注解Repository替代配置文件中的bean
@Repository("userDAO")
public class UserDaoImpl implements UserDAO {
@Override
public void save() {
System.out.println("save running...");
}
}
注意:
使用注解进行开发时,需要在spring-config.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便使用注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="com"></context:component-scan>
7.2 Spring新注解
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:
<bean>
- 加载properties文件的配置:
<context:property-placeholder>
- 组件扫描的配置:
<context:component-scan>
- 引入其他文件
<import>
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring配置类,当闯将容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器时要扫描的包 作用和在Spring的xml配置文件中的<context:component-scan base-package=“com”/>一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到Spring容器中 |
@PropertySource | 用于加载properties文件中的配置 |
@Import | 用于导入其他配置类 |
8、代理设计模式
代理的设计模式是为了实现什么功能呢?
就是为了动态的的监控功能一个类中方法在什么时候 执行 以及能在方法的执行前后 动态的植入我们的代码
8.1 静态代理
静态代理 和动态代理都有一个代理的前提
这个代理前提就是 这个被代理的类必须实现接口
,如果没有实现接口的话 那么这个代理是无法实现的
下面来实现一波
编写接口
public interface IUserService {
/**
* 更新数据
*/
void update();
/**
* 插入数据
*/
void insert();
}
实现类
public class UserService implements IUserService{
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
}
}
代理类
1、编写代理类和被代理的类 实现相同的接口
2、在代理类中维护被代理的类的对象
3、在构造器中进行被代理类的初始化
4、在相同的名字方法中 调用被代理类中的相同的名字的方法
5、在代理类中调用被代理的类的方法的时候 就可以进行方法的增强了
public class UserServiceProxy implements IUserService{
private IUserService userService;
public UserServiceProxy(IUserService userService){
this.userService=userService;
}
public void update() {
System.out.println("打开事务");
userService.update();
System.out.println("提交事务");
}
public void insert() {
System.out.println("打开事务");
userService.insert();
System.out.println("提交事务");
}
}
测试一波
public class Test001 {
public static void main(String[] args){
UserServiceProxy userServiceProxy = new UserServiceProxy(new UserService());
userServiceProxy.update();
}
}
8.2 动态代理
动态代理 相当于是静态代理的实现 只不过 在JDK中已经帮你实现了 所以动态代理 还有一个名字 JDK代理
实现一波
编写接口类
public interface IUserService {
/**
* 更新数据
*/
void update();
/**
* 插入数据
*/
void insert();
}
编写被代理的类
public class UserService implements IUserService {
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
}
}
编写代理类测试
public class Test001 {
@Test
public void testProxy(){
/**
* 第一个参数类加载器:这个固定的写法 被代理的类.class.getClassLoader()
* 类加载器是用来干嘛的? 记住这个类加载器 是用来 加载类的 找类的
* 第二个参数:当前这个代理的类实现的接口
* 1、被代理的是类 被代理的类.class.getInterfaces()
* 2、被代理的是接口 new Class[]{被代理的接口.class}
* 第三个参数:监控这个类中方法在什么时候 进行调用
* new Invocationhandler{
*
* ... invoke()....
*
* }
*/
IUserService userServiceProxy= (IUserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
UserService.class.getInterfaces(),
new InvocationHandler() {
/**
* 监控方法在什么时候 执行的
* @param proxy :代理类对象
* @param method :执行的目标方法
* @param args :执行方法需要的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("当前执行的方法是:"+name);
//你就可以执行目标方法了
//下面是反射执行方法 这个执行的是被代理类中的方法 所以只能使能被代理的类的对象来执行
Object invoke = method.invoke(new UserService(), args);
return invoke;
}
}
);
//调用被代理的方法
userServiceProxy.update();
}
}
8.3 CGLIB代理
动静态代理都是对实现了接口的类进行代理,那没实现接口的类就不能被代理了吗,这显然不合规矩,因此我们的CGLIB代理应运而生了 即CGLIB代理说的问题是:一个类 没有实现接口 也可以写代理
接下来玩一下
- 导包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
- 被代理类UserService
public class UserService {
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
}
}
- 编写代理类
public class UserServiceProxyFactory implements MethodInterceptor{
/**
* 这个位置就是生成代理类的地方
* @return
*/
public UserService getUserServiceProxy(){
Enhancer enhancer=new Enhancer();
//给生成的代理类整个爹
enhancer.setSuperclass(UserService.class);
//要监控他爹里面的方法在什么时候 进行调用
enhancer.setCallback(this);
return (UserService) enhancer.create();
}
/**
* 专门用来拦截监听我们类中的方法在什么时候调用
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
System.out.println("当前执行的方法是:"+name);
//执行的是 被代理的类中的方法
Object invoke = method.invoke(new UserService(), objects);
return invoke;
}
}
测试类
public class Test001 {
@Test
public void testCGLIBPRoxy(){
UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory();
UserService userServiceProxy = proxyFactory.getUserServiceProxy();
userServiceProxy.update();
}
}
9、AOP
AOP:是一种编程思想 类似于面向对象OOP
AOP究竟说的是啥? 简单说 就是我们在写代码的时候 有可能存在代码的重复(冗余) 这个时候 我们可以将这个代码抽取出来 专门放到一个类的方法中,然后当代码正常运行的时候 通过代理的设计模式
动态植入我们的代码 这种编程思想就叫做面向切面编程
在开发中你们有没有想过一个问题:就是我们的事务 如何控制?
在正常的开发中,我们的事务 不是添加到DAO层 ,而是添加到Service层的,因为一个业务的成功才代表了 一次操作的成功,所以在业务逻辑层上,所有的业务都应该有 打开事务 和 提交事务 的这个操作
简单点说 就是 每一个业务逻辑层的方法上 都有 打开事务 提交事务 的操作,如果是每一个方法我们都自己去写的话 那么代码会存在冗余 那么这个时候AOP就可以实现这个功能了
手动实现一个AOP
- 编写AOP类
@Component
public class Aop {
/**
* 打开事务
*/
public void startTransaction(){
System.out.println("....打开事务....");
}
/**
* 提交事务
*/
public void commitTransaction(){
System.out.println("....打开事务....");
}
}
- 编写UserService类
@Component
public class UserService {
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
}
}
- 编写代理类
package com.csdn.aop.sx;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Component
public class UserServiceProxyFactory implements MethodInterceptor{
@Autowired
private Aop aop;
@Autowired
private UserService userService;
/**
* 这个位置就是生成代理类的地方
* @return
*/
public UserService getUserServiceProxy(){
Enhancer enhancer=new Enhancer();
//给生成的代理类整个爹
enhancer.setSuperclass(UserService.class);
//要监控他爹里面的方法在什么时候 进行调用
enhancer.setCallback(this);
return (UserService) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
System.out.println("当前执行的方法是:"+name);
//调用aop的方法
aop.startTransaction();
//执行的是 被代理的类中的方法
Object invoke = method.invoke(userService, objects);
//调用aop的方法
aop.commitTransaction();
return invoke;
}
}
- 配置xml
<!--设置扫描Spring注解的位置-->
<context:component-scan base-package="com.csdn.aop.sx"></context:component-scan>
- 编写测试
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
UserServiceProxyFactory userServiceProxyFactory = context.getBean(UserServiceProxyFactory.class);
UserService userServiceProxy = userServiceProxyFactory.getUserServiceProxy();
userServiceProxy.update();
}
9.2 使用配置模式实现AOP
- 编写AOP类
package com.csdn.aop.config;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @author xiaobobo
*/
public class Aop {
/**
* 表示的是在执行目标方法之前执行
*/
public void before(){
System.out.println("----------before-----------");
}
/**
* 在执行了目标方法之后执行
*/
public void after(){
System.out.println("----------after-----------");
}
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("---------------环绕之前---------------");
proceedingJoinPoint.proceed();
System.out.println("---------------环绕之后---------------");
}
/**
* 在执行了目标方法有返回值的时候执行
*/
public void afterReturn(){
System.out.println("----------afterReturn-----------");
}
/**
* 抛出异常的时候执行
*/
public void afterThrowing(){
System.out.println("----------afterThrowing-----------");
}
}
- 编写UserService类
package com.csdn.aop.config;
import org.springframework.stereotype.Component
/**
* @author jimoji
* @date : 2022-11-19
*/
@Component
public class UserService {
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
}
}
- 编写配置文件spring-aop-config.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--全部使用配置来完成-->
<bean id="aop" class="com.csdn.aop.config.Aop"></bean>
<!--把这个类的对象放到IOC容器中去-->
<bean id="userService" class="com.csdn.aop.config.UserService"></bean>
<aop:config>
<!--下面配置切入点表达式? 所谓的切入点指的是我们的代码植入的位置
id:取名字 随便取 但是一般见名之意 pt
expression:配置的是切入点表达式
execution(* com.csdn.aop.config.UserService.*(..))
第一个 *:表示的是方法的返回值 因为可能有很多个 那么不知道 不知道就写 *
UserService.*:这里的这个 * :代表的是 这个类中的所有方法
(..) :表示的是不知道这些方法的参数是什么 所以写两个 .
-->
<aop:pointcut id="pt" expression="execution(* com.csdn.aop.config.UserService.*(..))"></aop:pointcut>
<!--下面配置咋们的切面-->
<aop:aspect ref="aop">
<aop:before method="before" pointcut-ref="pt"></aop:before>
<aop:after method="after" pointcut-ref="pt"></aop:after>
<aop:after-returning method="afterReturn" pointcut-ref="pt"></aop:after-returning>
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"></aop:after-throwing>
<aop:around method="around" pointcut-ref="pt"></aop:around>
</aop:aspect>
</aop:config>
</beans>
- 编写测试
package com.csdn.aop.config;
import com.csdn.aop.sx.UserServiceProxyFactory;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop-config.xml");
UserService userService = context.getBean(UserService.class);
userService.insert();
}
}
9.3 使用注解模式实现AOP
- 编写配置文件
<!--使能aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--设置Spring要扫描的这个包-->
<context:component-scan base-package="com.csdn.aop.anno"></context:component-scan>
- 编写aop类
@Component
@Aspect //表明当前的这个类 是一个切面类
public class Aop {
/**
* 定义切入点表达式
*/
@Pointcut(value = "execution(* com.csdn.aop.anno.UserService.*(..))")
public void pt(){
}
/**
* 表示的是在执行目标方法之前执行
*/
@Before(value = "pt()")
public void before(){
System.out.println("----------before-----------");
}
/**
* 在执行了目标方法之后执行
*/
@After(value = "pt()")
public void after(){
System.out.println("----------after-----------");
}
@Around(value = "pt()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("---------------环绕之前---------------");
proceedingJoinPoint.proceed();
System.out.println("---------------环绕之后---------------");
}
/**
* 在执行了目标方法有返回值的时候执行
*/
@AfterReturning(value = "pt()")
public void afterReturn(){
System.out.println("----------afterReturn-----------");
}
/**
* 抛出异常的时候执行
*/
@AfterThrowing(value = "pt()")
public void afterThrowing(){
System.out.println("----------afterThrowing-----------");
}
}
- 编写配置文件
<!--使能aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--设置Spring要扫描的这个包-->
<context:component-scan base-package="com.csdn.aop.anno"></context:component-scan>
- 编写UserService类
@Component
public class UserService {
public void update() {
System.out.println("-----------update------------");
}
public void insert() {
System.out.println("-----------insert------------");
throw new RuntimeException("出现了叽莫叽异常...");
}
}
- 编写测试类
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop-anno.xml");
UserService userService = context.getBean(UserService.class);
userService.insert();
}
}
10、Spring中DAO模块的使用(不用记)
1.导包
<!--Spring中的这个DAO实际导入的包是下面这个-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
- 编写DAO
package com.csdn.dao;
import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Repository
public class UserDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 查询所有的数据库的对象
*/
public List<User> selectList(){
return jdbcTemplate.query("select * from t_user", new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
//将结果集取出来 映射成一个Java对象?
//首先要获取列的数量
ResultSetMetaData metaData = resultSet.getMetaData();
//获取一共有几列数据
int columnCount = metaData.getColumnCount();
//遍历每一个行
while (resultSet.next()){
User user = new User();
//每一行又有columnCount多个列
for (int j = 0; j <columnCount ; j++) {
//获取列的名字
String columnName = metaData.getColumnName(j+1);
//再通过列的民资 获取列的值
Object val = resultSet.getObject(columnName);
//这里需要将键值对映射到User对象中去
try {
BeanUtils.copyProperty(user,columnName,val);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return user;
}
return null;
}
});
}
}
- 编写Service
package com.csdn.dao;
import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Service
public class UserService {
@Autowired
private UserDAO userDAO;
/**
* 查询所有的用户对象
* @return
*/
public List<User> findUserAll(){
List<User> userList = userDAO.selectList();
System.out.println("查询到的数据是:"+userList);
return userList;
}
}
- 编写全局配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--连接池需要配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置操作数据库的这个对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--设置Spring要扫描的这个包-->
<context:component-scan base-package="com.csdn.dao"></context:component-scan>
</beans>
- 编写测试
package com.csdn.dao;
import com.csdn.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-base-aop-dao.xml");
UserService userService = context.getBean(UserService.class);
List<User> userAll = userService.findUserAll();
System.out.println("返回的数据是:"+userAll);
}
}
11、Spring中的事务问题
以后做开发的时候要注意一个问题 :这个问题就是我们的事务 是应该添加到 业务逻辑层的方法上的
一个业务逻辑的成功与否 才代表了一次操作的成功与否
事务是添加到业务逻辑层的
11.1、通过配置方式实现Spring的事务
- 编写配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--连接池需要配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置操作数据库的这个对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置一个事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置我们的事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
name="*表示的是所有方法"
read-only="false":表示的是这些方法的事务类型是不是只读事务 如果是false表示的是读写事务
只读事务只适合于查询数据
读写事务 适合于增删改
-->
<tx:method name="*" read-only="false"/>
</tx:attributes>
</tx:advice>
<!--接下来配置aop-->
<aop:config>
<!--这个表示在哪里使用这个事务-->
<aop:pointcut id="pt" expression="execution(* com.csdn.tx.config.UserService.*(..))"></aop:pointcut>
<!--接下来配置应用事务增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
<!--设置Spring要扫描的这个包-->
<context:component-scan base-package="com.csdn.tx.config"></context:component-scan>
</beans>
- 编写DAO
package com.csdn.tx.config;
import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Repository
public class UserDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 查询所有的数据库的对象
*/
public List<User> selectList(){
return jdbcTemplate.query("select * from t_user", new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
//将结果集取出来 映射成一个Java对象?
//首先要获取列的数量
ResultSetMetaData metaData = resultSet.getMetaData();
//获取一共有几列数据
int columnCount = metaData.getColumnCount();
//遍历每一个行
while (resultSet.next()){
User user = new User();
//每一行又有columnCount多个列
for (int j = 0; j <columnCount ; j++) {
//获取列的名字
String columnName = metaData.getColumnName(j+1);
//再通过列的民资 获取列的值
Object val = resultSet.getObject(columnName);
//这里需要将键值对映射到User对象中去
try {
BeanUtils.copyProperty(user,columnName,val);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return user;
}
return null;
}
});
}
public void insert(){
jdbcTemplate.update("insert into t_user(username,password) values('abc','bcd')");
}
public void update(){
jdbcTemplate.update("update t_user set username='xxx'");
}
}
- 编写Service
package com.csdn.tx.config;
import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Service
public class UserService {
@Autowired
private UserDAO userDAO;
/**
* 查询所有的用户对象
* @return
*/
public List<User> findUserAll(){
List<User> userList = userDAO.selectList();
System.out.println("查询到的数据是:"+userList);
return userList;
}
public void testTranaction(){
userDAO.insert();
// int k=1/0;
userDAO.update();
}
}
- 编写测试
package com.csdn.tx.config;
import com.csdn.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-base-tx-config.xml");
UserService userService = context.getBean(UserService.class);
userService.testTranaction();
}
}
11.2 通过注解模式实现Spring的事务
- 编写配置文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd" >
<!--连接池需要配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置操作数据库的这个对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置一个事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--这个是使能这个事务的这个注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--设置Spring要扫描的这个包-->
<context:component-scan base-package="com.csdn.tx.anno"></context:component-scan>
</beans>
- 编写DAO
package com.csdn.tx.anno;
import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Repository
public class UserDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
jdbcTemplate.update("insert into t_user(username,password) values('abc','bcd')");
}
public void update(){
jdbcTemplate.update("update t_user set username='xxx'");
}
}
- 编写Service
package com.csdn.tx.anno;
import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.lang.model.type.ArrayType;
import java.sql.SQLException;
import java.util.List;
/**
* @author jimoji
* @date : 2022-11-19
*/
@Service
public class UserService {
@Autowired
private UserDAO userDAO;
/**
* rollbackFor:这个表示的是哪一个异常需要回滚 rollbackFor = Exception.class
* noRollbackFor:那个异常不需要回滚 noRollbackFor = ArithmeticException.class
* timeout:你可以给这个操作设置一个过期时间 过期了 那么也就不能操作了 -1:永远不过期
* isolation :设置事务的隔离级别 默认是可重复读 这个做开发不用设置
* propagation:事务的传输类型
* 这个是用在哪里的呢? 业务逻辑类调用业务逻辑类的场景 因为两个业务逻辑类 都有事务
* 问题来了 , 那么这两个事务 以谁为准呢?
* 如果是事务的传输类型是 Propagation.REQUIRED 那么A---->B 如果都有事务的话 那么会以A的事务为准 简单的说 b出错了 会引起A回滚
* 如果事务的传输类型是 Propagation.REQUIRES_NEW的话 那么A和B之间的事务是两个事务 相互之间没有影响
*
* readOnly = false:这个表示的是这个事务 是不是只读事务 一般增删改都需要读写事务所以这里需要设置成 false 如果是查询这里可以设置为true
*
*/
@Transactional(readOnly = false)
public void testTranaction(){
userDAO.insert();
int k=1/0;
userDAO.update();
}
}
- 编写测试
package com.csdn.tx.anno;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-tx-anno.xml");
UserService userService = context.getBean(UserService.class);
userService.testTranaction();
}
}
总结一波:
ringframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.lang.model.type.ArrayType;
import java.sql.SQLException;
import java.util.List;
/**
- @author jimoji
- @date : 2022-11-19
/
@Service
public class UserService {
@Autowired
private UserDAO userDAO;
/*- rollbackFor:这个表示的是哪一个异常需要回滚 rollbackFor = Exception.class
- noRollbackFor:那个异常不需要回滚 noRollbackFor = ArithmeticException.class
- timeout:你可以给这个操作设置一个过期时间 过期了 那么也就不能操作了 -1:永远不过期
- isolation :设置事务的隔离级别 默认是可重复读 这个做开发不用设置
- propagation:事务的传输类型
- 这个是用在哪里的呢? 业务逻辑类调用业务逻辑类的场景 因为两个业务逻辑类 都有事务
- 问题来了 , 那么这两个事务 以谁为准呢?
- 如果是事务的传输类型是 Propagation.REQUIRED 那么A---->B 如果都有事务的话 那么会以A的事务为准 简单的说 b出错了 会引起A回滚
- 如果事务的传输类型是 Propagation.REQUIRES_NEW的话 那么A和B之间的事务是两个事务 相互之间没有影响
- readOnly = false:这个表示的是这个事务 是不是只读事务 一般增删改都需要读写事务所以这里需要设置成 false 如果是查询这里可以设置为true
@Transactional(readOnly = false)
public void testTranaction(){
userDAO.insert();
int k=1/0;
userDAO.update();
}
}
4. 编写测试
```java
package com.csdn.tx.anno;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author jimoji
* @date : 2022-11-19
*/
public class Test001 {
@Test
public void testAop(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-tx-anno.xml");
UserService userService = context.getBean(UserService.class);
userService.testTranaction();
}
}
总结一波:
此教程很适合刚入门的小伙伴查阅,里边涉及了Spring的五个模块的知识点,写的真的很详细,原创属实不易,希望小伙伴们多多支持。嘿嘿,感兴趣的给个关注