使用spring自定义事务(待)
2022.01.09-2022.01.16
1,Spring
1.1,简介
Spring起源与interface21
Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
spring的理念:使现有技术更加容易使用,本身是一个大杂烩
官网:https://spring.io/projects/spring-framework
源码地址:https://repo.spring.io/ui/native/release/org/springframework/spring
Github地址:https://github.com/spring-projects/spring-boot
maven核心依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.14</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.14</version>
</dependency>
1.2,spring优点
- 开源免费的框架(容器)
- 轻量级(依赖包很小)的、非入侵式(对以前的框架影响不大)的框架
- 控制反转(IOC)、面向切面(AOP)
- 支持对事务的处理,对框架整合的支持
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3,组成
1.4,扩展
现代化的java开发——基于spring开发
- SpringBoot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速开发单个微服务
- 约定大于配置
- SpringCloud
- SpringCloud是基于SpringBoot开发
大多数的公司都是使用SpringBoot进行快速开发,规模更大的公司使用SpringCloud进行集群开发。学习springBoot的前提是学习Spring和spingMvc!
弊端:发展太久后,违背了原来的初衷(使开发更加容易),杂糅的东西太多,配置十分繁琐(人称“配置地狱”)。
2,IOC理论推导
原有的代码编程流程:daoImpl→dao→serviceImpl→service
缺点:每次修改需求都会涉及到底层的引用修改,如果修改代码的量比较大(代价昂贵)就得不偿失!
public class UserServiceImpl implements UserService {
// private UserDao userDao = new UserDaoImpl();
// private UserDao userDao = new UserDaoPgImpl();
private UserDao userDao;
// 利用set方法实现动态注入
@Override
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
- 之前,程序是主动创建对象!控制权在程序员手中
- 使用set注入后,程序不再具有主动性,而是变成了被动的接收对象
这种思想,从本质上解决了问题:程序员不用再去管理对象的创建,系统的耦合性大大降低,可以更加专注于业务的实现上!(IOC的原型)
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
3,HelloSpring
使用beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用spring创建对象
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 对象名称
class = new的对象(本质与import一致)
properties 给属性设置值
-->
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<property name="str" value="wanyu"></property>
</bean>
</beans>
最基础的容器获取
public class XmlIocTest {
public static void main(String [] args) {
// 获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象现在都在Spring中管理了,使用的时候直接取出即可
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
当然还有其他的注入方式,例如现在主要使用的注解注入以及其他的文件注入。
IOC一句话概括就是:由spring创建、管理、装配对象!
由容器创建的对象是单例
public class XmlIocTest {
public static void main(String [] args) {
// 获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/beans.xml");
// 我们的对象现在都在Spring中管理了,使用的时候直接取出即可
Hello hello = (Hello) context.getBean("hello");
Hello hello2 = (Hello) context.getBean("hello");
System.out.println(hello == hello2);
}
}
/*
true
*/
直接使用SpringXml装配
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDaoPg" class="com.example.springboothelloworld.web.dao.impl.UserDaoPgImpl"/>
<bean id="userDaoMysql" class="com.example.springboothelloworld.web.dao.impl.UserDaoMysqlImpl"/>
<bean id="userDao" class="com.example.springboothelloworld.web.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.example.springboothelloworld.web.service.impl.UserServiceImpl">
<!-- ref:引入spring中已经创建好的对象 -->
<property name="userDao" ref="userDaoPg"/>
</bean>
</beans>
public class IocTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/user.xml");
UserService userService = (UserService) context.getBean("userService");
userService.getUser();
}
}
4,IOC创建对象方式
1,无参构造创建对象(默认)
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<property name="str" value="wanyu"/>
</bean>
public class XmlIocTest {
public static void main(String [] args) {
// 获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/beans.xml");
// 我们的对象现在都在Spring中管理了,使用的时候直接取出即可
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
}
2,使用有参构造创建对象
public class Hello {
private String str;
public Hello(String str) {
this.str = str;
System.out.println("有参构造初始化hello对象! ");
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public void show(){
System.out.println("数据=>"+str);
}
}
①下标幅值
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<constructor-arg index="0" value="wanyu"/>
</bean>
②类型幅值
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<constructor-arg type="java.lang.String" value="wanyu"/>
</bean>
③入参名幅值
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<constructor-arg name="str" value="wanyu"/>
</bean>
在配置文件加载的时候,容器中管理的对象就已经初始化了
5,Spring配置
5.1,别名
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello">
<constructor-arg name="str" value="wanyu"/>
</bean>
<alias name="hello" alias="helloRandom"/>
// 获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/beans.xml");
// 我们的对象现在都在Spring中管理了,使用的时候直接取出即可
Hello hello = (Hello) context.getBean("helloRandom");
hello.show();
5.2,Bean的配置
name本质也是一个别名,可以一次设置多个(空格和逗号分割)
<bean id="hello" class="com.example.springboothelloworld.bean.pojo.Hello" name="hello2,h2 h3">
<constructor-arg name="str" value="wanyu"/>
</bean>
// 获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/beans.xml");
// 我们的对象现在都在Spring中管理了,使用的时候直接取出即可
Hello hello = (Hello) context.getBean("h2");
hello.show();
5.3,import
一般用于团队开发,可以将多个配置文件(例如:beans.xml和user.xml)导入合并为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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml"/>
<import resource="user.xml"/>
</beans>
6,DI(依赖注入)
Dependency Injection
6.1,构造器注入
详情见【4,IOC创建对象方式】
6.2,Set方式注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
// getter、setter、toString略
}
student.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.example.springboothelloworld.bean.pojo.Student">
<!-- 1,普通值注入 -->
<property name="name" value="wanyu"/>
<!-- 2,引用注入 -->
<property name="address" ref="address"/>
<!-- map -->
<property name="card">
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="phone" value="123456"/>
<entry key="idCard" value="42061111"/>
</map>
</property>
<!-- 数组 -->
<property name="books">
<array>
<value>java并发</value>
<value>集群</value>
<value>jvm Hotspot</value>
</array>
</property>
<property name="hobbys">
<list>
<value>打游戏</value>
<value>听歌</value>
<value>骑车</value>
</list>
</property>
<property name="games">
<set>
<value>lol</value>
<value>wow</value>
<value>原神</value>
</set>
</property>
<property name="wife">
<value></value>
</property>
<property name="info">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
<bean id="address" class="com.example.springboothelloworld.bean.pojo.Address">
<property name="location" value="杭州"/>
</bean>
</beans>
输出:
Student{name='wanyu', address=Address{location='杭州'}, books=[java并发, 集群, jvm Hotspot], hobbys=[打游戏, 听歌, 骑车], card={phone=123456, idCard=42061111}, games=[lol, wow, 原神], wife='', info={jdbc.url=jdbc:mysql://localhost:3306/mydb, jdbc.driver.className=com.mysql.jdbc.Driver}}
6.3,扩展方式注入
p-namespace and c-namespace injection
p-namespace(set方法)
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="student-p" class="com.example.springboothelloworld.bean.pojo.Student" p:name="wanyu"/>
</beans>
c-namespace(构造方法)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="student-c" class="com.example.springboothelloworld.bean.pojo.Student" c:name="wanyu-c"/>
</beans>
注意点:p 和 c命名空间注入需要额外应用xml约束
6.4,作用域
bean scope
样例:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
<bean id="accountService2" class="com.something.DefaultAccountService" scope="prototype"/>
其他的request、session、application等在下个springMVC学习(挖坑)
7,自动装配
- Spring满足bean依赖一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在spring中有三种装配方式:①xml中显式配置;②java中显式配置;③隐式的自动装配bean
7.1,原始的显示装配
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="cat" class="com.example.springboothelloworld.bean.pojo.Cat"/>
<bean name="dog" class="com.example.springboothelloworld.bean.pojo.Dog"/>
<bean id="people" class="com.example.springboothelloworld.bean.pojo.People">
<property name="name" value="wanyu-people"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
</beans>
7.2,byType & byName
<!-- 会自动在容器上下文查找,和自己对象set方法后面对应的bean byType类型 byName根据名称 -->
<bean id="people" class="com.example.springboothelloworld.bean.pojo.People" autowire="byName">
<property name="name" value="wanyu-people"/>
</bean>
- byName时,需要保证所有bean的id唯一,并且这个bean需要和自动注入属性值一致
- byType时,需要保证所有bean的class唯一,并且这个bean需要和自动注入属性值一致
7.3,使用注解自动装配
jdk1.5支持注解,spring2.5支持注解装配
前提条件:
①导入约束(context约束);
②配置注解的支持; context:annotation-config/
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
样例:
public class People {
// 说明该对象可以为null,否则不允许为空
// @Autowired(required = false)
// javax的注解也可以实现自动装配
@Resource
private Dog dog;
@Autowired
// 指定特定的对象
@Qualifier(value = "cat2")
private Cat cat;
private String name;
// getter\setter略
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean name="cat1" class="com.example.springboothelloworld.bean.pojo.Cat"/>
<bean name="cat2" class="com.example.springboothelloworld.bean.pojo.Cat"/>
<bean name="dog" class="com.example.springboothelloworld.bean.pojo.Dog"/>
<bean id="people" class="com.example.springboothelloworld.bean.pojo.People"/>
</beans>
- @Resource 和 @Autowired的区别
- 都是用来自动装配的,可以放在属性字段上
- @Autowired通过byType的方式实现
- @Resource默认通过byName的实现,如果找不到名称,则通过byType实现,如果两个都找不到,就报错(unique error)
8,使用注解开发
在spring4之后,要使用注解开发就需要导入aop(面向切片编程)的包
1,bean
10,代理模式
为什么要学习代理模式?SpringAOP的底层(无侵入式编程!!!牛皮)
角色分析:
- 抽象角色:一般使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实的角色,代理后可以做一些附加操作(AOP)
- 客户:访问代理对象的角色
代理模式的好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共的业务交给代理去完成!实现业务的分工
- 公共业务发生扩展的时候,方便集中管理
动态代理的好处:
- 一个动态代理类代理的是一个接口,一般就是对应的业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口
10.1,静态代理
缺点:
- 一个真实角色就会产生一个代理角色(代码量会暴增、开发效率堪忧)
// 抽象角色
public interface Rent {
void rent();
}
// 真实角色
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
// 代理角色
public class Proxy {
private Host host;
public void setHost(Host host) {
this.host = host;
}
public void rent(){
seeHouse();
sign();
host.rent();
fare();
}
public void seeHouse(){
System.out.println("中介带人看房");
}
public void sign(){
System.out.println("中介签合同");
}
public void fare(){
System.out.println("中介收费");
}
}
// 测试
public class StaticProxyTest {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rent();
}
}
/*
中介带人看房
中介签合同
房东出租房子
中介收费
*/
10.2,动态代理
public class ProxyInvocationHandler implements InvocationHandler {
private Object object;
public void setObject(Object object) {
this.object = object;
}
public Object getProxy() {
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
object.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
log(method.getName());
return method.invoke(object, args);
}
public void log(String msg) {
System.out.println("执行" + msg + "方法! ");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
Host host = new Host();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setObject(host);
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
/*
执行rent方法!
房东出租房子
*/
11,AOP
11.1,什么是aop
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。——百度百科
11.2,AOP在Spring中的作用
声明式事务,允许用户自定义切面
- 横切关注点:跨越应用多个模块的方法和功能。例如:与我们的业务逻辑无关,但是我们需要关注的部分,就是横切关注点。日志,安全、缓存、事务。。
- 切面(aspect):横切关注点 被模块化 的特殊对象。即,一个类
- 通知(advice):切面需要完成的任务。即,一个方法
- 目标(target):被通知的对象
- 代理(proxy):向目标对象通知后创建的对象
- 切入点(pointCut):切面通知 执行的“地点”的定义
- 连接点(joinPoint):与切入点匹配的执行点
Spring中的5种类型的advice:
10.3,使用Spring的AOP
【重点】使用AOP织入,导入aspectweaver包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方法一:使用【spring API】自带的接口
// service层
public interface UserAopService {
public String add();
public void delete();
public void update();
public void query();
}
// serviceImpl层
public class UserAopServiceImpl implements UserAopService {
@Override
public String add() {
System.out.println("增加");
return "success";
}
@Override
public void delete() {
System.out.println("删除");
}
@Override
public void update() {
System.out.println("更新");
}
@Override
public void query() {
System.out.println("查询");
}
}
// logAfter
public class LogAfter implements AfterReturningAdvice {
/**
*
* @param returnValue 执行后的返回结果
* @param method
* @param args
* @param target
* @throws Throwable
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法执行后的结果为=>"+returnValue);
}
}
// logBefore
public class LogBefore implements MethodBeforeAdvice {
/**
*
* @param method 要执行目标对象的方法
* @param args 参数
* @param target 被通知的对象
*/
@Override
public void before(Method method, Object[] args, Object target) {
System.out.println(target.getClass().getName()+"类的"+method.getName()+"方法【将要】被执行!");
}
}
// AopTest
public class AopTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-properties/AopSpring.xml");
UserAopService userAopService = (UserAopService) context.getBean("userAopService");
userAopService.add();
userAopService.query();
}
}
/*
com.example.springboothelloworld.web.service.impl.UserAopServiceImpl类的add方法【将要】被执行!
增加
add方法执行后的结果为=>success
com.example.springboothelloworld.web.service.impl.UserAopServiceImpl类的query方法【将要】被执行!
查询
query方法执行后的结果为=>null
*/
<!-- xml注入 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<bean id="userAopService" class="com.example.springboothelloworld.web.service.impl.UserAopServiceImpl"/>
<bean id="logBefore" class="com.example.springboothelloworld.bean.pojo.LogBefore"/>
<bean id="logAfter" class="com.example.springboothelloworld.bean.pojo.LogAfter"/>
<!-- 导入aop的切入点 -->
<!-- 方式1:使用原生的Spring API接口 -->
<!-- 配置aop:需要导入aop的约束 -->
<aop:config>
<!--切入点:expression表达式,execution(要执行的位置! ****)-->
<aop:pointcut id="pointcut"
expression="execution(* com.example.springboothelloworld.web.service.impl.UserAopServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/>
</aop:config>
</beans>
方法二:使用自定义类来实现【切面定义】
该方法相对于方法一功能稍微差一些,原因是它无法获知具体的类和方法
public class CustomeLog {
public void before(){
System.out.println("==方法执行之前==");
}
public void after(){
System.out.println("==方法执行之后==");
}
}
/*
==方法执行之前==
增加
==方法执行之后==
==方法执行之前==
查询
==方法执行之后==
*/
<!--方法2:自定义类-->
<bean id="customeLog" class="com.example.springboothelloworld.bean.pojo.CustomeLog"/>
<aop:config>
<!--自定义切面 ref 要引用的类-->
<aop:aspect ref="customeLog">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.example.springboothelloworld.web.service.impl.UserAopServiceImpl.* (..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
方法三:使用注解实现
// 注解实现的aop
@Aspect
public class AnotationPointCut {
@Around("execution(* com.example.springboothelloworld.web.service.impl.UserAopServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Signature signature = jp.getSignature();
System.out.println(signature);
// 执行方法
Object proceed = jp.proceed();
System.out.println("环绕后");
}
}
/*
环绕前
signature:String com.example.springboothelloworld.web.service.UserAopService.add()
增加
环绕后
环绕前
signature:void com.example.springboothelloworld.web.service.UserAopService.query()
查询
环绕后
*/
<!--方式三:注解实现aop-->
<bean id="anotationPointCut" class="com.example.springboothelloworld.common.AnotationPointCut"/>
<!--开启注解支持: JDK(默认proxy-target-class="false") cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
12,声明式事务
12.1,什么是事务:
- 把一组业务当成一个业务来做!要么全部成功、要么全部失败(原子性)
- 事务在项目开发中,十分重要,涉及到数据的一致性问题
- 确保完整性和一致性
事务的ACID原则:
- 原子性Atomicity(要么全部成功、要么全部失败)
- 一致性Consistency(事务的前后,数据库中的数据的状态要确保一致---高并发、锁)
- 隔离性Isolation(多个事务可能操作同一个数据,防止数据损坏)
- 持久性Durability(事务一旦提交后,不会被影响,被持久化写入存储区中)
12.2,spring中的事务管理
- 声明式事务:AOP
- 编程式事务:需要在代码实现事务管理
为什么需要事务?
- 如果不配置事务,可能会出现数据提交不一致的情况下;
- 如果我们不在spring中配置声明式事务,我们就需要在代码中手动配置事务
- 事务在项目开发中十分重要,涉及到数据的一致性和完整性问题
参考链接
2,Spring官网