Spring学习笔记
1、简介
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级的、非入侵式的框架
- 控制反转((IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
总结一句话: Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.14</version>
</dependency>
2、IOC本质
- 控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有lOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
- 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
- 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,Dl)。
3、XML创建实体对象
3.1 创建实体类Hello
package pojo;
// 只有无参构造函数
public class Hello {
private String str;
/*
public Hello(String name){
this.str = name;
}
*/
public String getStr() {
return str;
}
public void setStr( String str ) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
3.2 Spring配置文件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">
<!-- 无参构造 -->
<bean id="hello" class="pojo.Hello">
<!-- value放基本类型 -->
<property name="str" value="Spring"/>
</bean>
<bean id="hello2" class="pojo.Hello2">
<!-- ref放Spring容器中已经创建好的对象 -->
<property name="hel" ref="hello"/>
</bean>
<!-- 有参构造 -->
<!-- 第一种,下标赋值 -->
<bean id="user" class="com. kuang.pojo.User">
<constructor-arg index="0" value="狂神说Java" />
</bean>
<!-- 第二种方式:通过类型创建,不建议使用! -->
<bean id="user" class="com. kuang.pojo.user">
<constructor-arg type="java.lang.String" value="ginjiang"/>
</bean>
<!-- 第三种,直接通过参数名来设置,推荐 -->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="秦疆"/>
</bean>
</beans>
- 编写完成后记得配置应用程序上下文
3.3 测试运行
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Hello;
public class MyTest {
@Test
public void Test() {
// 获取Spring的上下文对象!
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
// 我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
Hello hello = (Hello) context.getBean( "hello" );
System.out.println( hello.toString() );
//输出:Hello{str='Spring'}
}
}
4、Spring配置
4.1 别名
- 别名和原名都能够取到对象
<!-- Beans.xml中 -->
<!-- 方式1 -->
<alias name="user" alias="userNew" />
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
// 以下两种均可
Hello hello = (Hello) context.getBean( "user" );
Hello hello = (Hello) context.getBean( "userNew" );
4.2 Bean的配置
<!--
id : bean的唯一标识符,也就是相当于我们学的对象名
class : bean对象所对应的全限定名:包名+类型
name :也是别名,而且name可以同时取多个别名,空格、逗号、分号都能做分隔
-->
<bean id="userT" c1ass="com.kuang.pojo.userT" name="user2 u2,u3;u4">
<property name="name" value="西部开源"/>
</bean>
4.3 import
这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个配置文件。
假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中。
我们可以利用import将所有人的beans.xml合并为一个总的!
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
使用的时候,使用总的配置就可以了
正式的总配置文件名为applicationContext.xml
5、依赖注入
5.1 构造器注入
见3.2 Spring配置文件Beans.xml
5.2 set方式注入(重点)
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;
}
<bean id="student" class="com.kuang.pojo.Student">
<!-- 第一种,普通值注入, value -->
<property name="name" value="xx"/>
<!-- 第二种,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>
</list>
</property>
<!-- Map -->
<property name="card">
<map>
<entry key="身份证" value="111111222222223333"/>
<entry key="银行卡" value="1321231312312313123"/>
</map>
</property>
<!-- Set -->
<property name="games">
<set>
<value>LOL</value>
<value>coc</value>
<value>BOB</value>
</set>
</property>
<!-- null -->
<property name="wife">
<nu11/>
</property>
<!-- 或者 -->
<property name="wife" value="" />
<!-- Properties -->
<property name="info">
<props>
<prop key="driver">xxx</prop>
<prop key="ur1">xxx</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
5.3 拓展方式注入
5.3.1 p命名空间注入
<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">
<bean id="bar" class="x.y.Bar"/>
<!-- p命名空问注入,可以直接注入属性的值: property -->
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"
p:test-ref="bar" />
</beans>
- 注意导入schema:xmlns:p="http://www.springframework.org/schema/p"
5.3.2 C命名空间注入
<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">
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
<!-- 传统声明 -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean>
<!-- c命名空间声明 -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>
</beans>
- 注意导入schema:xmlns:c="http://www.springframework.org/schema/c"
5.4 Bean的作用域
-
单例模式 Singleton(Spring默认机制)
<bean id="user2" class="pojo.user" c:age="18" scope="singleton" />
-
原型模式 Prototype :每次从容器中getBean的时候,都会产生一个新对象!
<bean id="user2" class="pojo.user" c:age="18" scope="prototype" />
-
其余的request、session、application只能在Web开发中使用到。
6、Bean的自动装配
- 自动装配是 Spring 满足 bean 依赖的一种方式!
- Spring 会在上下文中自动寻找,并自动给 bean 装配属性!
- 在 Spring 中有三种装配的方式
- 在 XML 中显式配置
- 在 Java 中显式配置
- 隐式的自动装配 bean
<!-- 传统注入 -->
<beans>
<bean id="cat" class="pojo.cat" />
<bean id="dog" class="pojo.Dog" />
<bean id="people" class="com.kuang.pojo.people">
<property name="name" value="xxxx"/>
<property name="dog" ref="dog" />
<property name="cat" ref="cat"/>
</bean>
</beans>
6.1 ByName自动装配
<beans>
<bean id="cat" class="pojo.cat" />
<bean id="dog" class="pojo.Dog" />
<!-- byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id -->
<bean id="people" class="com.kuang.pojo.people" autowire="byName">
<property name="name" value="xxxx"/>
</bean>
</beans>
6.2 ByType自动装配
<beans>
<bean class="pojo.cat" />
<bean class="pojo.Dog" />
<!-- byType:会自动在容器上下文中查找,和自己对象属性类型(class)相同的bean -->
<bean id="people" class="com.kuang.pojo.people" autowire="byType">
<property name="name" value="xxxx"/>
</bean>
</beans>
小结:
-
byName 的时候,需要保证所有 bean 的 id 存在且唯一,并且这个 bean 需要和自动注入的属性的 set 方法的值一致!
-
byType 的时候,需要保证所有 bean 的 class 存在且唯一,并且这个 bean 需要和自动注入的属性的类型一致!
6.3 使用注解实现自动装配
使用注解须知:
-
导入约束
-
配置注解的支持:<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> <bean>...</bean> </beans> </beans>
6.3.1 @Autowired
直接在属性上使用!也可以在set方式上使用!
使用@Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性Type在 Spring 容器中存在,且符合名字byName!
<beans>
<bean id="cat11" class="pojo.cat"/>
<bean id="cat111" class="pojo.cat" />
<bean id="dog22" class="pojo.Dog" />
<bean id="dog222" class="pojo.Dog" />
<bean id="people" class="pojo.People" />
</beans>
public class People {
@Autowired
private cat cat;
//@Autowired无法实现时,要配合@qualifier(value="")来针对某一个bean进行装配
@Autowired
@Qualifier(value="dog222")
private Dog dog;
private string name;
}
6.3.2 @Resource
public class People {
@Resource(name = "cat11")
private cat cat;
@Resource
private Dog dog;
}
@Resource 和 @Autowired 的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired 先通过byType的方式实现,后通过byName,而且必须要求这个对象存在!【常用】
- @Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
小结:
-
@Autowired 先byType,如果同类型个数大于1,再byName。
-
dog只注册了一个的时候,dog的id可以随便取都能自动装配相当于byType。当dog注册了多个时,只能绑定id和person属性名一样的bean相当于byName,如果多个都没有对应的id就报错
-
如果 @Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value="xxx") 去配置 @Autowired 的使用,指定一个唯一的bean对象注入!
这个value对应的是bean的id,相当于byName。
7、使用注解开发
在 Spring 4 之后,要使用注解开发。必须要保证 aop 的包导入了!
使用注解需要导入 context 约束,增加注解的支持。
<?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:component-scan base-package="pojo"/>
<context:annotation-config/>
</beans>
7.1 常用注解
7.1.1 @Autowired
- 通过类型、名字,自动装配
- 如果 @Autowired 不能唯一装配上属性,则需要通过 @Qualifier( value = "xxx" ) 指定唯一bean
7.1.2 @Resource
- 通过名字、类型,自动装配
7.1.3 @Nullable
- 字段标记了这个注解,说明这个字段可以为null
7.1.4 @Component
- 组件,放在类上,说明这个类被 Spring 管理了,成为Bean。
//等价于:<bean id="user" class="pojo.user"/>
@Component
public class User {
public string name;
public void setName(string name) {
this.name = name;
}
}
7.1.5 @Value
- @Value( ) 放在属性或set方法上均可。
@component
public class User {
//相当于 <property name="name" value="kuangshen" />
@Value( "kuangshen2")
public string name;
public void setName( String name ) {
this.name = name;
}
}
7.1.6 @Scope
@component
//确定作用域:单例或原型
@scope("prototype")
public class User {
public string name;
@Value( "kuangshen2")
public void setName( String name ) {
this.name = name;
}
}
7.2 衍生的注解
-
@Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层!
- dao【@Repository】
- service【@Service】
- controller【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到 Spring 容器中,装配Bean。
8、使用 Java 的方式(注解)配置 Spring
我们现在要完全不使用 Spring 的 XML 配置了,全权交给 Java来做!
JavaConfig 是 Spring 的一个子项目,在 Spring 4 之后,它成为了一个核心功能
package config;
import pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// 这个也会由Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration代表这是一个配置类,就和我们之前看的applicationContext.xml一样
@configuration //相当于<beans>
@ComponentScan( "pojo" ) //扫描某个包下的所有@Component
@Import(AppConfig2.class)
public class AppConfig {
// 注册一个bean ,就相当于我们之前写的一个<bean>标签
// 这个方法的名字,就相当于bean标签中的id属性
// 这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User user() {
return new User();
}
}
- 测试
public class MyTest {
public static void main(string[] args) {
// 如果完全使用了配置类方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器
// 通过配置类的class对象加载!
Applicationcontext context = new
AnnotationConfigApplicationContext(Appconfig.class);
User user = (user) context.getBean("user");
System.out.println(user.getName());
}
}
9、代理模式
9.1 静态代理
- 代理对象和真实对象都有共同的接口
- 客户直接通过代理对象直接调用方法
- 在代理类中静态扩展代码
9.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);
}
//处理代理实例,并返回结果:
public object invoke(0bject proxy,Method method,object[] args) throws Throwable {
log(method.getName());
object result = method.invoke(target, args);
return result;
}
public void log(string msg){
system.out.println("执行了" + msg + "方法");
}
}
public class client {
public static void main( string[ ] args) {
//真实角色 (实现类)
UserServiceImpl userService = new UserServiceImpl();
//创建代理生成类的实例
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userservice); //设置要代理的对象
//代理角色 (动态生成代理类)
UserService proxy = (UserService) pih.getProxy();
proxy.query();
}
}
动态代理相对于静态代理的好处:
无需编写代理类:对于静态代理,每个类都要写对应的代理类,会多出许多冗余的类;而动态代理,仅需通过一个代理生成类,动态生成对应类的对应代理对象,减少了代码量。
10、AOP
10.1 图解AOP
- 什么叫面向切面编程?这就是:
10.2 Spring 实现 AOP
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
10.2.1 使用原生 Spring API
<!-- 注册bean -->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<!-- com.kuang.log.beforeLog 里面实现了 MethodBeforeAdvice 接口的 before 方法 -->
<bean id="beforeLog" class="com.kuang.log.Log"/>
<!-- com.kuang.log.afterLog 里面实现了 AfterReturningAdvice 接口的 afterReturning 方法 -->
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!-- 方式一:使用原生Spring API接口 -->
<!-- 配置aop:需要导入aop的约束 -->
<aop:config>
<!-- 切入点: expression:表达式,execution(要执行的位置!* * ***) -->
<aop:pointcut id="pointcut" expression="execution(* com.kuang. service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加! -->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />
</aop:config>
10.2.2 自定义类实现
<!-- applicationContext.xml -->
<bean id="diy" class="com.kuang.diy.DiyPointCut" />
<aop:config>
<!-- 自定义切面, ref要引用的类 -->
<aop:aspect ref="diy" >
<!-- 切入点 -->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="point" />
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
10.2.3 注解实现AOP
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut" />
<!-- 开启注解支持! -->
<aop:aspectj-autoproxy />
//方式三:使用注解方式实现AOP
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
@Aspect //标注这个类是一个切面
public class AnnotationPointcut {
@Before( "execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
system.out.println( "=======方法执行前======" );
}
@After( "execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
system.out.println( "=======方法执行后======" );
}
// 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点;
// 可以获取切入点的相关信息。
@Around( "execution(*com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
system.out.println("环绕前");
object proceed = jp.proceed(); //执行方法
system.out.println("环绕后");
}
}
10.3 Spring AOP 五大通知
-
Before 前置通知
-
AfterReturning 后置通知
-
Around 环绕通知
-
AfterThrowing 异常通知
-
After 最终通知
五种通知的执行顺序
在目标方法没有抛出异常的情况下
前置通知 → 环绕通知的调用目标方法之前的代码 → 目标方法 → 环绕通知的调用目标方法之后的代码 →
后置通知 → 最终通知
在目标方法抛出异常的情况下
前置通知 → 环绕通知的调用目标方法之前的代码 → 目标方法 → 抛出异常 异常通知 → 最终通知
11、整合Mybatis
详细内容可以查看文档
11.1 基础方式
-
导入相关Jar包
- Junit
- Mybatis
- MySQL数据库
- Spring 相关
- AOP 织入
- mybatis-spring 【new】
-
编写 Spring 、Mybatis 配置文件
<!-- spring-dao.xml --> <!-- 数据库的配置,一般不改,直接import进 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: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"> <!-- DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 我们这里使用Spring提供的JDBC:org.springframework.jdbc.datasource --> <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?useSSL=true"/> <property name="username" value="root" /> <property name="password" value="123456"/> </bean> <!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="datasource" ref="datasource"/> <!-- 绑定Mybatis配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml" /> <property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/> </bean> <!-- sqlSessionTemplate:就是我们使用的sqlSession --> <bean id="sqlSession" class="org.mybatis.spring.sqlsessionTemplate"> <!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法 --> <constructor-arg index="0" ref="sqlSessionFactory" /> </bean> </beans>
<!-- appplicationContext.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 https://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="spring-dao.xml"/> <!-- Mapper的实现类 --> <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl"> <property name="sqisession" ref="sqlsession" /> </bean> </beans>
-
写 Mapper.xml(sql语句)
......
-
写 Mapper 的实现类 MapperImpl
import org.mybatis.spring.sqlSessionTemplate; import java.util.List; public class UserMapperImpl implements UserMapper { private sqlsessionTemplate sqlsession; public void setSqlSession(sqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectuser(); } }
11.2 SqlSessionDaoSupport
- 实现类去掉属性 sqlSession 和 set 方法
- 直接通过getSqlSession()获取sqlSession,无需注入依赖
import org.mybatis.spring.sqlSessionTemplate;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectuser();
}
}
同时,在 spring-dao.xml 中去掉:
<!-- sqlSessionTemplate:就是我们使用的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.sqlsessionTemplate">
<!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法 -->
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
并修改:
<!-- Mapper的实现类 -->
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqisession" ref="sqlsession" />
</bean>
<!-- 修改为 -->
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<!-- 父类 SqlSessionDaoSupport 需要 sqlSessionFactory工厂实例 -->
<property name="sqlSessionFactory" ref="sqlsessionFactory" />
</bean>
12、事务
12.1 什么叫事务?
- 把一组业务当成一个业务来做;要么都成功,要么都失败!
- 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎!·确保完整性和一致性;
- 事务ACID原则:
- 原子性:一个事务要么全部执行,要么不执行。
- 一致性:数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性。
- 隔离性:多个业务可能操作同一个资源,防止数据损坏。
- 持久性:事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中。
12.2 Spring 事务管理
- 声明式事务:AOP
- 编程式事务:需要在代码中,进行事务的管理
为什么需要事务?
如果不配置事务,可能存在数据提交不一致的情况。
如果我们不在 Spring 中去配置声明式事务,我们就需要在代码中手动配置事务!
事务在项目的开发中十分重要,设计到数据的一致性和完整性问题,不容马虎!
12.3 Spring 声明式事务
<!-- spring-dao.xml -->
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务(需要结合事务的方法丢进去) -->
<!-- 配置事务的传播特性: propagation -->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED" />
<tx:method name="query" read-only="true" />
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入 -->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!