爬坑Spring
[TOC]
Spring简介
1.1 官网
1.2 理念
使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
1.3 优点
Spring是一个开源的免费的框架(容器)
Spring是一个轻量级的、非侵入式的框架
控制权反转 IOC,面向切面编程 AOP
支持事务的处理,对框架整合的支持
1.4 组成
1.5 拓展
Spring boot
- 一个快速开发的脚手架。
- 基于Spring Boot可以快速开发单个微服务。
- 约定大于配置。
Spring Cloud
- 基于Spring Boot实现的。
== 现在大部分公司都在使用Spring Boot进行快速开发,学习Spring Boot的前提,需要完全掌握Spring 及 SpringMVC ==
Spring弊端:发展太久后违背了最初理念,配置十分繁琐,直至Spring Boot的出现
IOC
2.1 IOC的推导
2.1.1 初识控制权反转
- UserDao 接口
- UserDaoImpl 接口实现类
- UserService 业务接口
- UserServiceImpl 业务实现类
IOC原型之静态生成对象–控制权掌握在程序员手中
public class UserServiceImpl implements UserService{
private UserDao userDao =new UserDaoMysqlImpl();
public void getUser() {
userDao.getUser();
}
}
public class MyTest {
public static void main(String[] args) {
//用户调用业务层,dao无需接触
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();
}
}
通过new的方式,在service层静态的,固定的给出了业务实现,用户无法进行控制。
IOC原型之动态生成对象–控制权掌握在用户手中
public class UserServiceImpl implements UserService{
private UserDao userDao;
//使用set进行注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
通过set方法注入,使得service层动态加载业务,具体业务的种类的选择权转移到了用户手中。
public class MyTest {
public static void main(String[] args) {
//用户调用业务层,dao无需接触
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
- 过去,如图1,我们希望在四个模块中间有一个中间件进行联系,那么我们只需要调用中间件即可访问其他模块
- 于是乎IOC容器诞生了,由IOC容器连接模块,模块间不再具有强耦合性,用户决定调用的方向。
总结:控制权反转(IOC),是一种使得程序从主动改变转换为被动接收,将控制权由开发人员手中转移到用户手中的设计思想而非具体实现方法,DI(依赖注入)是实现IOC的一种方法
控制权反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制权反转的是IOC容器,其实现的方法为依赖注入(Dependency Injection,DI)
2.1.2 第一个Spring程序
配置文件的编写
使用XML
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="Mysql" class="com.chengzzz.dao.UserDaoMysqlImpl"/>
<bean id="oracle" class="com.chengzzz.dao.UserDaoOracleImpl"/>
<bean id="user" class="com.chengzzz.dao.UserDaoImpl"/>
<bean id="userservices" class="com.chengzzz.service.UserServiceImpl">
<!--
ref:引用容器中创建好的对象
value:具体的值
-->
<property name="userDao" ref="user"></property>
</bean>
</beans>
以上Bean类通过在XML中声明后,即可通过ApplicationContext ApplicationContext = new ClassPathXmlApplicationContext("beans.xml")读取到配置文件,从而使得IOC容器实现控制权反转
public class MyTest {
public static void main(String[] args) {
ApplicationContext ApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userservices = ApplicationContext.getBean("userservices",UserServiceImpl.class);
userservices.getUser();
}
}
以上即为Spring通过xml 实现控制权反转后产生的实体类对象,通过getBean方法获取并得以使用
使用注解
使用纯java代码
IOC对象的创建
IOC创建对象的方式
无参构造器创建对象,默认方法
<bean id="hello" class="com.chengzzz.pojo.Hello"> <property name="name" value="小橙子"></property> </bean>
有参构造创建对象
下标注入
<bean id="hello" class="com.chengzzz.pojo.Hello"> <constructor-arg index="0" value="小橙子"></constructor-arg> </bean>
类型注入
<bean id="hello" class="com.chengzzz.pojo.Hello">
<constructor-arg type="java.lang.String" value="小橙子"></constructor-arg>
</bean>
参数名注入
<bean id="hello" class="com.chengzzz.pojo.Hello">
<constructor-arg name="name" value="小橙子"></constructor-arg>
</bean>
Spring配置
3.1 alisas(别名)
<alias name="hello" alias="hello2"></alias>
没什么卵用
<bean id="hello" class="com.chengzzz.pojo.Hello" name="hello2,hello1">
<constructor-arg name="name" value="小橙子"></constructor-arg>
</bean>
在bean的注册中可以使用name来写入别名
3.2 Import
导入配置文件,团队开发中,含有多个配置文件时可以使用import将所有的配置文件合并为一个。
<import resource="beans1.xml"></import>
<import resource="beans2.xml"></import>
<import resource="beans3.xml"></import>
注意重名时,后导入的会覆盖前导入的
DI(依赖注入)
4.1 构造器注入
参考上文 IOC创建对象的方式
4.2 Set方法注入
Set方法注入【重点】
- Set注入是依赖注入的本质,依赖注入的本质是Set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,都由容器来注入
测试环境
Student类
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;
/*get set tosting方法省略*/
}
Address类
public class Address {
private String address;
/*get set tosting方法省略*/
}
beans.xml
<bean id="student" class="com.chengzzz.pojo.Student">
<!--普通值注入-->
<property name="name" value="小橙子"></property>
</bean>
<bean id="address" class="com.chengzzz.pojo.Address"></bean>
完整注入xml
<bean id="student" class="com.chengzzz.pojo.Student">
<!--1.普通值注入 value-->
<property name="name" value="小橙子"></property>
<!--2.bean注入 ref-->
<property name="address" ref="address"></property>
<!--3.数组注入 ref-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
</array>
</property>
<!--4.list注入-->
<property name="hobbys">
<list>
<value>打游戏</value>
<value>听歌</value>
<value>睡觉</value>
</list>
</property>
<!--5.map注入-->
<property name="card">
<map>
<entry key="身份证" value="111"></entry>
<entry key="银行卡" value="222"></entry>
<entry key="校园卡" value="333"></entry>
</map>
</property>
<!--6.set注入-->
<property name="games">
<set>
<value>lol</value>
<value>wow</value>
</set>
</property>
<!--7.null注入-->
<property name="wife">
<null></null>
<!--8.Properties注入-->
</property>
<property name="info">
<props>
<prop key="drive">12333</prop>
<prop key="sex">女</prop>
</props>
</property>
</bean>
<bean id="address" class="com.chengzzz.pojo.Address"></bean>
4.3 拓展方式注入
P命名空间注入(p=property即属性注入)
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--p命名空间注入--> <bean id="user" class="com.chengzzz.pojo.User" p:name="小橙子" p:age="18"/> </beans>
C命名空间注入(c=constructor-arg即构造器注入)
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--c命名空间注入--> <bean id="user2" class="com.chengzzz.pojo.User" c:name="小橙子" c:age="19"/> </beans>
注意 p命名空间注入为属性注入即set注入 而set注入必须有无参构造器 c命名空间为有参构造器注入 实体类需重写有参构造方法
c命名空间 p命名空间不能直接使用 需要导入依赖
4.4 Bean的作用域
单例模式【Spring默认模式】
<bean id="user2" class="com.chengzzz.pojo.User" c:name="小橙子" c:age="19" scope="singleton"/>
原型模式
<bean id="user2" class="com.chengzzz.pojo.User" c:name="小橙子" c:age="19" scope="prototype"/>
其余的request、sesstion、application只在web开发中使用到
Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式。
- Spring会在上下文中自动寻找,并自动给bean装配属性
Spring中装配方式有三种
- 在xml中显式地配置
- 在java中显式地配置
- 隐式的自动装配bean 【重要】
5.1测试
测试类
public class Cat {
public void shout(){
System.out.println("喵喵喵");
}
}
public class Dog {
public void shout(){
System.out.println("汪汪汪");
}
}
public class People {
private Cat cat;
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;
}
}
配置文件
<bean id="cat" class="www.chengzzz.pojo.Cat"></bean>
<bean id="dog" class="www.chengzzz.pojo.Dog"></bean>
<bean id="people" class="www.chengzzz.pojo.People">
<property name="name" value="xxx">
</property>
<property name="cat" ref="cat">
</property>
<property name="dog" ref="dog"></property>
</bean>
5.2 自动装配的方式
byName(在容器上下文中查找和自己对象set方法后面的值对应的beanid) 名字必须唯一
<bean id="people" class="www.chengzzz.pojo.People" autowire="byName"> <property name="name" value="xxx"/> </bean>
byType(在容器上下文中查找和自己对象属性类型相同的bean)
<bean id="people" class="www.chengzzz.pojo.People" autowire="byType"> <property name="name" value="xxx"> </property> </bean>
小节
- byname的时候。需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法值一致。
- bytype的时候。需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
5.3 使用注解实现自动装配
JDK从1.5开始支持的注解,Spring从2.5就开始支持注解
使用注解注意点
导入约束
<!–hexoPostRenderEscape:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd">
</beans>:hexoPostRenderEscape–>
- 开启注解支持
<context:annotation-config/>
在属性上直接使用也可以在set方法上使用,实体类可以没有set方法前提是符合byType
@Autowired
@Qualifier(value = "cat") //此注解可指定自动装配name为cat的bean
Tips
@Nullable //字段标记了这个注解 说明这个字段可以为null
@Autowired(required=false) //表示这个对象可以为null
@Resource //jdk的注解,亦可指定@Resource(name="cat") 此注解在jdk11中被移除
@Resource和@Autowired的区别
- 都是用来自动装配的,都可以放在属性字段上
- @AutoWired默认通过byType实现,必须要求其存在,否则空指针
- @Resource默认通过byName方式实现,如果找不到名字则通过byType实现,如果找不到则报错。
使用注解开发
在Spring4之后 要使用注解开发,必须导入aop的包
需要导入context的约束,开启注解支持
注解
@Component //声明此类为自动装配的组件,配合自动扫描包实现自动装配
@Value("小橙子") //赋值,相当于属性注入中的value
@Repository //Dao层的标注Component的衍生注解
@Service //Service层的标注Component的衍生注解
@Controller //Controller层的标注Component的衍生注解
@AutoWired //自动装配的注解
@Scope //模式注解
@Configuration //使用java代码实现xml配置
@ComponentScan("com.chengzzz.pojo")//扫描指定的包
@Import(bean2.class) //导入另外的配置文件
@Aspect //切面
xml与注解
- xml更加万能,维护简单方便
- 注解不是自己的类使用不了,维护相对复杂
xml与注解的最佳实现
- xml用来管理bean
- 注解只负责属性的注入
- 我们在使用的过程中只需要注意一个问题:必须让注解生效,就必须开启注解支持。
6.1 开启注解支持
<!--开启注解支持-->
<context:annotation-config/>
<!--指定需要扫描的包,这个包下的注解会生效-->
<context:component-scan base-package="com.chengzzz.pojo"/>
6.2 使用JavaConfig实现配置
我们现在完全使用java来实现配置
JavaConfigs Spring的一个子项目,在Spring4之后,他成为了一个核心功能
@Configuration
@ComponentScan("com.chengzzz.pojo")
@Import(bean2.class)
public class MyConfig {
@Bean
public User getUser(){
return new User();
}
}
这种纯Java的配置方式,在SpringBoot中随处可见
AOP
Spring Aop支持五种类型
需要导入依赖包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
7.1 代理模式
为什么要学习代理模式?
因为这就是SpringAop的底层【SpringAop和SpringMVC】
代理模式的分类:
- 静态代理
- 动态代理
7.1 静态代理
角色分析:
- 抽象角色:一般使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色 ,代理真实角色后,我们一般会做一些附加操作
- 客户:访问代理对象的角色
静态代理模式的好处:
- 可以使得真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共业务交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候方便集中管理
静态代理模式的缺点:
- 一个真实角色就会产生一个代理角色:代码量翻倍,开发效率变低
AOP初识
7.2 动态代理
- 动态代理和静态代理角色一样
- 动态代理的类是动态生成的,不是直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口—-JDK动态代理
- 基于类—-cglib
- 基于java字节码—-javassist
需要了解两个类 Proxy:代理,InvocationHandler:调用处理程序
//重写这个类,实现自动代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//动态代理就是利用反射机制实现
Object result = method.invoke(target, objects);
return result;
}
}
public class User {
public static void main(String[] args) {
//真实角色
App app = new App();
//代理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setTarget(app);
Download proxy = (Download) proxyInvocationHandler.getProxy();
proxy.download();
}
}
public interface Download {
void download();
}
public class App implements Download{
@Override
public void download() {
System.out.println("下载");
}
}
动态代理的优点:
- 可以使得真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共业务交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候方便集中管理
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
7.2 AOP实现方式一
使用Spring的api
public class beforlog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(o1.getClass().getName()+"----"+method.getName());
}
}
<bean id="services" class="com.chengzzz.services.ServicesImpl"/>
<bean id="log" class="com.chengzzz.log.beforlog"/>
<aop:config>
<!--注册切点-->
<aop:pointcut id="point" expression="execution(* com.chengzzz.services.ServicesImpl.*(..))"/>
<!--注册切入方式-->
<aop:advisor advice-ref="log" pointcut-ref="point"/>
</aop:config>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Services services = context.getBean("services", Services.class);
services.query();
}
}
由于动态代理代理的是接口,所以getBean时,需要转换为接口
7.3 AOP实现方式二
使用自定义类实现aop
public class DiyPointCut {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
<!--切面对象-->
<bean id="diypoint" class="com.chengzzz.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面-->
<aop:aspect ref="diypoint" >
<!--注册切点-->
<aop:pointcut id="point" expression="execution(* com.chengzzz.services.ServicesImpl.*(..))"/>
<!--注册通知,通知spring 什么时候(method="before" 即动态代理前后) 对切点执行什么方法(DiyPointCut中的方法)-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Services services = context.getBean("services", Services.class);
services.query();
}
}
由于动态代理代理的是接口,所以getBean时,需要转换为接口
7.4 AOP实现方式三
使用注解方式实现
@Aspect
public class Annolog {
@Before("execution(* com.chengzzz.services.ServicesImpl.*(..))")
public void before(){
System.out.println("注解前置增强");
}
}
<!--注入注解切面类-->
<bean id="annolog" class="com.chengzzz.log.Annolog"/>
<!--开启自动代理注解支持-->
<!--JDK默认proxy-target-class="false" 若为true 则使用cglib实现 结果无任何区别-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
tips @Around时,方法中可有参数ProceedingJoinPoint 以此获取部分信息
@Around("execution(* com.chengzzz.services.ServicesImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("注解环绕前"+joinPoint.getSignature());
Object proceed = joinPoint.proceed();
System.out.println("注解环绕后"+proceed);
}
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Services services = context.getBean("services", Services.class);
services.query();
}
}
由于动态代理代理的是接口,所以getBean时,需要转换为接口
整合Mybatis
导入jar包
- junit
- mybatis
- mysql
- spring
- aop
- mybatis-spring
<!–hexoPostRenderEscape:
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency><groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope>
</dependency>
<!– https://mvnrepository.com/artifact/mysql/mysql-connector-java –>
<!– 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-webmvc –>
<dependency><groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.7.RELEASE</version>
</dependency>
<!– https://mvnrepository.com/artifact/org.springframework/spring-jdbc –>
<dependency><groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.7.RELEASE</version>
</dependency>
<!– https://mvnrepository.com/artifact/org.aspectj/aspectjweaver –>
<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>
</dependencies>:hexoPostRenderEscape–>
- 编写配置文件
- 测试
8.1 整合方式一
mybatis-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 http://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="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
>
<property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 创建SqlSessionFactory MyBatis会话工厂对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:com/chengzzz/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.chengzzz.pojo"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" >
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="mybatis-config.xml"/>
<bean id="userMapper" class="com.chengzzz.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
Tips 注意 若未配置别名,mapper中返回类型需完整路径
实现过程
- 编写数据源配置
- sqlSessionFactory
- sqlSessionTemplate
- 需要给接口加实现类
- 将实现类注入Spring
- Test
8.2 整合方式二
在usermapper的实现类中继承SqlSessionDaoSupport
通过spring的api来获取sqlTemplate
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> selectList() {
return getSqlSession().getMapper(UserMapper.class).selectList();
}
}
同时在spring中注册这个bean时
<bean id="userMapper2" class="com.chengzzz.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
将sqlSessionFactory注入即可省略sqlSessionTemplate的配置
声明式事务
9.1 事务特点
- 将一组业务视为一个业务来实现,要么都成功,要么都失败
- 事务在项目开发中,十分重要,涉及到数据的一致性问题,不能马虎
- 确保完整性和一致性
9.2 事务的ACID原则
原子性 确保都失败或都成功。
一致性 确保资源状态统一。
隔离性
- 多个业务操作同一个资源时,防止数据损坏。
持久性
- 事务一旦提交无论系统发生什么问题,结果都不会再被影响,被持久化地写到存储器中。
9.3 声明式事务的使用
- 声明式事务:AOP的应用,非侵入式,横切
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--使用AOP实现事务的织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--事务的7种传播特性-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务的切入-->
<aop:config>
<aop:pointcut id="point" expression="execution(* com.chengzzz.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
- 编程式事务:需要在代码中,进行事务的管理
Tips
为什么需要事务?
- 如果不配置事务,可能存在数据提交不一致的情况
- 如果我们不在Spring中去配置声明式事务,就需要在代码中手动配置事务
- 事务在项目的开发中,十分重要涉及到数据的一致性和完整性问题,不容马虎