Spring概述、IoC和AOP
本文参考狂神说
一、spring概述
二、springIoC
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>com.lxf</groupId>
<artifactId>20200602-spring-study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!--字集模块-->
<modules>
<module>spring-01-ioc</module>
<module>spring-02-hellospring</module>
<module>spring-04-di</module>
<module>spring-05-Autowired</module>
<module>spring-06-anno</module>
<module>spring-07-appConfig</module>
<module>spring-08-proxy</module>
<module>spring-09-aop</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
1. Ioc容器管理对象
实体类Hello:
package com.lxf.pojo;
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
beans.xml(通常叫applicationContext.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来创建对象,在spring这些都称为Bean-->
<!--以前由自己创建对象,现在由spring帮你创建对象,也就是控制反转IoC-->
<bean id="hello" class="com.lxf.pojo.Hello">
<property name="str" value="Spring" />
</bean>
</beans>
测试类MyTest:
import com.lxf.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
//对象在spring管理,用直接取
Hello hello = (Hello) context.getBean("hello");
//或者Hello hello = context.getBean("hello",Hello.class);
//打印这个对象
System.out.println(hello);
}
}
2. Ioc容器依赖注入
(1)无标签的set注入
实体类Address:
package com.lxf.pojo;
public class Address {
private String address;
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
实体类Student:
package com.lxf.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> game;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGame() {
return game;
}
public void setGame(Set<String> game) {
this.game = game;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", game=" + game +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
实体类User:
package com.lxf.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
beans.xml(通常叫applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.lxf.pojo.Address">
<property name="address" value="中国"/>
</bean>
<bean id="student" class="com.lxf.pojo.Student">
<!--普通值注入-->
<property name="name" value="lxf"/>
<!--bean的ref注入-->
<property name="address" ref="address"/>
<!--数组注入-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
</array>
</property>
<!--list注入-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>打游戏</value>
<value>打代码</value>
</list>
</property>
<!--map注入-->
<property name="card">
<map>
<entry key="身份证" value="1234567890"/>
<entry key="银行卡" value="9876543210"/>
</map>
</property>
<!--set注入-->
<property name="game">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<!--null注入-->
<property name="wife">
<null/>
</property>
<!--property注入-->
<property name="info">
<props>
<prop key="Num">20190525</prop>
<prop key="url">男</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
(2)无标签的construtor注入
实体类User:
package com.lxf.pojo;
public class User {
private String name;//名字
private int age;//年龄
private String sex;//性别
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
userbeans.xml(通常叫applicationContext.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">
<!--index下标标识-->
<bean id="user" class="com.lxf.pojo.User">
<constructor-arg index="0" value="刘一手"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
<constructor-arg index="2" value="男"></constructor-arg>
</bean>
<!--type标识-->
<bean id="user" class="com.lxf.pojo.User">
<constructor-arg type="java.lang.String" value="刘一手"></constructor-arg>
<constructor-arg type="java.lang.Integer" value="18"></constructor-arg>
<constructor-arg type="java.lang.String" value="男"></constructor-arg>
</bean>
</beans>
(3)带标签的依赖注入(p标签代替properties,c标签代替constructor-arg):
实体类User:
package com.lxf.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
userbeans.xml(通常叫applicationContext.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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p标签注入-->
<bean id="user" class="com.lxf.pojo.User" p:name="刘一手" p:age="18" />
<!--c标签注入-->
<bean id="user2" class="com.lxf.pojo.User" c:_0="刘二手" c:_1="19"/>
</beans>
3. 自动装配
(1)无扫描的注解装配
实体类cat:
package com.lxf.pojo;
public class Cat {
public void shout(){
System.out.println("miao~");
}
}
实体类dog:
package com.lxf.pojo;
public class Dog {
public void shout(){
System.out.println("wang~");
}
}
实体类People:
package com.lxf.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Autowired
private Cat cat;
@Autowired //先bytype,后byname,spring注解
//@Resource,先byname,后bytype,java注解
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
beans.xml(一般名为:applicationContext.xml)
<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">
<bean id="cat3" class="com.lxf.pojo.Cat"/>
<bean id="cat" class="com.lxf.pojo.Cat"/>
<bean id="dog" class="com.lxf.pojo.Dog"/>
<bean id="people" class="com.lxf.pojo.People"/>
<!--
byName:容器中查找和自己的set方法后面名字相同对应的bean的id
byType:容器中查找和自己的set方法后面类型相同对应的bean的id
-->
<!--<bean id="people" class="com.lxf.pojo.People" autowire="byName">
<property name="name" value="王得发" />
</bean>-->
<!--开启注解支持,直接在people类中用注解配置-->
<context:annotation-config />
</beans>
测试类MyTest:
import com.lxf.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取上下文对象
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
//从容器中取到people对象
People people = context.getBean("people", People.class);
//调用(已装载)
people.getDog().shout();
people.getCat().shout();
System.out.println("people = " + people);
}
}
(2)带扫描的注解装配
controller层:
package com.lxf.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}
Dao层:
package com.lxf.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
pojo层:
package com.lxf.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//等于在容器中注册
@Component
//@Scope(value = "prototype")
@Scope(scopeName = "singleton")
public class User {
@Value("刘一手")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
service层:
package com.lxf.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
}
application.xml:
<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 />
<!--扫描支持-->
<context:component-scan base-package="com.lxf"/>
</beans>
测试类MyTest:
import com.lxf.pojo.User;
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");
//获取User
User user=context.getBean("user", User.class);
//打印结果
System.out.println("user.name = " + user.getName());
}
}
(3)无配置文件的装配
config类:
package com.lxf.config;
import com.lxf.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//@Import(User.class) //导入合并其他配置类,类似于配置文件中的 inculde 标签
//@ComponentScan("com.lxf.pojo") //扫描包
public class LxfConfig {
@Bean
public User getUser(){
return new User();
}
}
User实体类:
package com.lxf.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("lxf")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
测试类MyTest:
import com.lxf.config.LxfConfig;
import com.lxf.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取上下文对象
ApplicationContext context=new AnnotationConfigApplicationContext(LxfConfig.class);
//获取User
User user = (User) context.getBean("getUser");
//打印结果
System.out.println(user.getName());
}
}
4.Bean的作用域
- singleton:单例模式(默认),意思:当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例
- prototype:原型模式,意思:当一个bean的作用域为prototype,那么每次Spring IoC容器中获取的bean实例都是不同的
- request:请求域,意思:当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;
- application:服务器域,意思:当一个bean的作用域为application,从服务器开始到结束都是一个bean定义对应一个实例;
- session:会话域,意思:当一个bean的作用域为session,表示在HTTP一次会话中,一个bean定义对应一个实例;
三、springAOP(面向切面编程)
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
理解:就是对动态代理的进一步封装,springAop代理真实类对象,然后对进行真实类对象切入,根据切入点分了5种类型通知(顺序、返回值、异常),可自己选择添加与否。
示例:
pom.xml的依赖:
<!--aop包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
了解动态代理对理解AOP有很好的帮助作用:静态代理与动态代理
application.xml:
<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.lxf.service.UserServiceImpl"/>
<bean id="log" class="com.lxf.log.Log"/>
<bean id="afterLog" class="com.lxf.log.AfterLog"/>
<!--方式一:使用原生spring api接口-->
<!--配置aop:需要导入aop约束-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.lxf.service.UserServiceImpl.*(..))"/>
<!--执行环绕通知-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut" />
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />
</aop:config>
<!--方式二:自定义类-->
<bean id="diy" class="com.lxf.diy.DiyPointCut"/>
<aop:config>
<!-- 自定义切面-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.lxf.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
<!--方式三-->
<bean id="annotationPointCut" class="com.lxf.diy.AnnotationPointCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
service层:
Userservice接口:
package com.lxf.service;
public interface UserService {
void add();
void delete();
void update();
void query();
}
UserserviceImpl实现类:
package com.lxf.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 query() {
System.out.println("查询了一个用户");
}
}
1.方式一(使用原生spring api接口):
log包:
Log类:
package com.lxf.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
AfterLog类:
package com.lxf.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[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue);
}
}
2.方式二:
diy包:
自定义DiyPointCut类:
package com.lxf.diy;
public class DiyPointCut {
public void before(){
System.out.println("=================方法执行前===================");
}
public void after(){
System.out.println("=================方法执行后===================");
}
}
3.方式三:
diy包:
AnnotationPointCut包
package com.lxf.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.lxf.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("==========方法执行前===========");
}
@After("execution(* com.lxf.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("==========方法执行后===========");
}
//在环绕中,可以给定一个参数,代表要获取处理切入的点
@Around("execution(* com.lxf.service.UserServiceImpl.*(..))")
public void round(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("==========环绕前===========");
//System.out.println("signatrue"+ joinPoint.getSignature());
//执行方法
joinPoint.proceed();
System.out.println("==========环绕后==========");
}
}
四、声明式事务
1.回顾事务
- 把一组业务当成一个业务;要么成功,要么都失败!
- 事务在项目开发中,十分重要,设计到数据的一致性问题,不能马虎!
- 确保完整性和一致性
事务的ACID原则:
- 原子性:事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性:一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性:可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性:一旦事务完成,无论发生什么系统发生什么问题,它的结果都不应该受到影响,事务的结果被写到持久化存储器中。
2.spring中的事务管理
- 声明式事务:AOP
- 编程式事务:需要在代码中,进行事务的管理(一般不用)
2.1、Spring中七种Propagation类的事务属性详解:
** REQUIRED:**支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (默认值)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
2.2事务隔离级别: 隔离级别是指若干个并发的事务之间的隔离程度。
DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是READ_COMMITTED。
READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
2.3applicationContext的配置:
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的转播特性:new 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.lxf.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
思考:
为什么配置事务?
- 如果不配置事务,可能存在数据提交不一致的情况
- 如果我们不在SPRING中去配置声明式事务,我们就需要在代码中手动配置事务!
- 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!