Spring5 学习
简介
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
导包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.10</version>
</dependency>
优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级的、非入侵式的框架!
- 控制反转(IOC)面向切面编程(AOP)!
- 支持事务的处理,对框架整合的支持!
Spring组成及扩展
组成
ORM 对象关系映射
现代化的开发:基于spring的开发
springboot:
- 一个快速开发的脚手架:
- 基于SpringBoot 可以快速的开发单个微服务
- 约定大于配置
SpringCloud
- SpringCloud是基于SpringBoot 实现的
弊端: 违背了 当初的理念,需要配置大量的东西
IOC理论推导
创建UserDao接口,以减少代码;系统的耦合性降低
IOC本质
控制反转(inversion of control), 是一种设计思想,DI(dependency injection依赖注入)是IOC的一种方法。未使用IOC的程序中,我们使用面向对象编程,对象的创建和对象之间的依赖关系完全硬编码在程序中,对象的创建是由程序自己控制的。控制反转就是将对象的创建转移给了第三方.IOC就我认为是:获得依赖对象的方式反转了
DI只是实现IOC的一种方法
IOC是Spring框架的核心内容, 使用了多种方式完美的实现了IOC,xml配置与注解形式,新版本的spring也可以零配置实现IOC
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
Hello Spring
Spring 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
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
对象是由Spring创建的,对象的属性是由Spring 设置的 这个过程就叫做控制反转
具体使用
ref 引用Spring容器中已经创建好的对象
value是所创建的对象的具体的值
对象由Spring来创建 管理 和分配
IOC创建对象方式
使用构造器创建对象
-
使用无参构造器 创建对象
-
使用有参构造创建对象
-
使用下标赋值法创建对象
<bean id="hello" class="com.hai.spring.pojo.Hello"> <constructor-arg index="0" value="海洪健" /> </bean>
-
使用类型进行赋值
<bean id="hello" class="com.hai.spring.pojo.Hello"> <constructor-arg type="java.lang.String" value="海洪健"/> </bean> 但是这种方法不建议使用 当有多个参数类型相同时,容易出现错误
-
直接通过参数名设置
<bean id="hello" class="com.hai.spring.pojo.Hello"> <constructor-arg name="str" value="海洪健" /> </bean>
-
在配置文件加载的时候,容器中管理的对象就已经初始化了
Spring配置说明
别名
<alias name="hello" alias="hello2"/>
改成什么都可以使用
Bean的配置 通过配置来实现IOC
<bean id="hello" class="com.hai.spring.pojo.Hello" name="hello2 hello3,hello4">
<property name="str" value="海洪健"/>
</bean>
<!-- id bean的唯一标识 相当于创建对象时 的对象名
class bean 对象所对应的全限定名 包名+类型
name 也是别名 而且name还可以取多个别名
-->
import配置
一般用于团队开发,可以将多个配置文件导入合并为一个
<import resource=""/>
DI 依赖注入环境
三种方式 构造器注入
构造器注入
constructor-arg 这种方式 就属于构造器注入
Set方式注入(重点) 要写 set方法
依赖注入:set注入
依赖:bean 对象的创建依赖于容器
注入:bean对象中的所有属性,由容器来注入
第一种:普通值注入 value
<bean id="student" class="com.hai.spring.pojo.Student">
<property name="name" value="海洪健"/>
</bean>
第二种: 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>RAP</value>
<value>打篮球</value>
</list>
</property>
第五种:map注入
<property name="card">
<map>
<entry key="身份证号" value="371482200001011100"/>
<entry key="年龄" value="21"/>
</map>
</property>
第六种:set注入
<property name="games">
<set>
<value>LOL</value>
<value>COD</value>
<value>王者</value>
</set>
</property>
第七种:空值注入
<property name="info">
<props>
<prop key="学号">202031008010</prop>
<prop key="成绩">98</prop>
</props>
</property>
扩展方式注入
c命名和p命名空间注入方式
p命名空间
<!-- p 命名空间 可以直接注入属性的值 P:property 相当于property -->
<bean id="user" class="com.hai.spring.pojo.User" p:name="海洪健" p:age="19">
<!-- <property name="name" value="海洪健"/>-->
<!-- <property name="age" value="19"/>-->
</bean>
c命名空间
<!-- c命名空间注入 相当于构造器注入-->
<bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20"/>
注意点:p命名空间和c命名空间 不可以直接使用 需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
Bean的作用域
默认的是单例模式 也可以显示的定义
单例模式 默认是单例模式
<bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20" scope="singleton"/>
原型模式
<bean id="user2" class="com.hai.spring.pojo.User" c:name="赵聪" c:age="20" scope="prototype"/>
原型模式会产生两个不同的对象,并且是每次get,都会产生一个新的对象
这里的get获取bean
其余的都是在web开发中会用到
自动装配bean
- 自动装配是满足bean依赖的一种方式
- Spring会在上下文中自动寻找,被自动给bean装配属性
在Spring中有三种装配方式
- 在xml中显示的配置
- 在Java中显示的进行配置
- 隐式的自动装配bean
ByName自动装配 通过名字来是实现自动装配
xml配置
<bean id="cat" class="com.hai.spring.pojo.Cat"></bean>
<bean id="dog" class="com.hai.spring.pojo.Dog"></bean>
<bean id="people" class="com.hai.spring.pojo.People" autowire="byName">
<property name="name" value="海洪健"/>
</bean>
java测试代码
一个人 两个宠物 两个宠物只有方法的实现 没有成员变量
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
People people = context.getBean("people",People.class);
System.out.println(people.getName());
people.getCat().shut();
people.getDog().shut();
}
byType 通过类型查找
!-- ByTYpe 自动装配会自动在容器的上下文中查找 与自己的类型相同的beanId 但是它有弊端 必须得保证类型全局唯一-->
<bean id="people" class="com.hai.spring.pojo.People" autowire="byType">
<property name="name" value="海洪健"/>
</bean>
小结:
- byname的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一样
- bytype的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一样
使用注解进行自动装配
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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
">
<!-- 扫描包含注解定义的类包-->
<context:annotation-config/>
</beans>
@Autowired自动装配注解
@Autowired
可以直接在属性上使用 也可以在set方法上使用
使用@Autowired 我们可以不用写set方法了 前提是你这个自动装配的属性在IOC(Spring) 容器中是存在的,且命名符合ByName
@nullable 字段标记了这个注解,说明这个字段可以为null;
public void setName(@Nullable String name) {
this.name = name;
}
使用nullable标记了这个注解 说明这个字段可以为空 并且还不会报错
@Autowired自动装配注解参数设置
注解装配在属性上
@Autowired(required = false)
private Dog dog;
required = false 将required设置为空 说明这个对象可以为null,否则不允许为空
@Qualifier 在id名和class名都不相同时。可以结合使用Qualifier 来实现自动装配 Qualifier 中有一个参数为value 专门用来解决这个问题
@Resource Java注解
@Resource
private Dog dog;
这个注解先通过 名字(name)进行查找 名字查找不到 通过类型进行查找 如果名字和类型都查找不到,才会报错
@Resource(name = "dog")
也可以通过指定名字进行注解
小结
@Resource和@Autowired 之间的区别
- 都是用来自动装配的,都可以放在字段上
- @Autowired 是通过byType的方式实现的,而且必须要求这个对象存在 通过类型来实现
- @Resource 默认通过byName 的方式来实现,如果找不到名字,则通过byTYpe来实现,如果两个都找不到,则进行报错
通过名字来实现 - 执行顺序不同,@Autowired 通过byType来实现
Spring注解开发
在Spring4之后,如果想使用注解进行开发,必须导入aop的包
Component
组件 使用方法为放到类上 说明这个类被Spring管理了 就是bean
属性注入
@Value("海洪健")
public String name;
通过value可以设置值 简单的可以使用 复杂的推荐使用配置文件
衍生的注解
在web开发中每一层都有自己的注解
dao @Repository
controller @Controller
service @service
bean @Component
这四个注解的功能都是一样的 都是将某个类注册到Spring容器中
xml与注解之间的区别
- xml更加的万能,适用与任何的场合!维护也相对简单。
- 注解 不是自己的类使用不了,维护相对的复杂!
xml与注解的最佳实现:
- xml只用来管理
- 注解只负责完成属性的注入;
- 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持。
使用JavaConfig实现配置
User类
package com.hai.spring.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 自动注解
@Component
public class User {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Value("海洪健")
public void setName(String name) {
this.name = name;
}
}
config 类
// @Configuration @Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
// 要求
//@Configuration不可以是final类型;
//@Configuration不可以是匿名类;
//嵌套的configuration必须是静态类。
package com.hai.spring.config;
import com.hai.spring.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 获取新的用户 这个注解用于定义配置类 可替换 xml配置文件
@Configuration
public class MyConfig {
@Bean
public User getUser() {
return new User();
}
}
测试类
package com.hai.test;
import com.hai.spring.config.MyConfig;
import com.hai.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestOne {
// context 获取Spring的上下文对象
// 获取ApplicationContext 拿到Spring容器
// 我们的对象都在Spring进行管理了,如果要使用,直接取出来就可以了
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
代理模式
为什么要学习代理模式? 因为代理模式就是Spring-Aop 的底层
SpringAop 和 SpringMvc重点 公司都会问
静态代理模式
代理就是帮我做事情 和中介查不多
角色分析:
抽象角色: 一般会用接口或者是抽象类来解决
真实角色: 被代理的角色
代理角色: 代理真实角色,代理真实角色后,我们一般会做一些附属操作
客户:访问代理角色的人
代理模式的好处:
- 可以使真实角色的操作更加的纯粹。不用去关心一些公共的事务
- 公共事务交给代理角色。实现了业务的分工
- 公共业务发生扩展时,方便集中管理
缺点:
- 一个真实的角色就会产生一个代理角色,这样会导致代码量翻倍。开发效率会变低。解决这个问题的方法就是动态代理
代理的步骤:
-
租房子接口
public class Rent { public void rent(); }
-
房东租房子 实现接口
public class host implements Rent{ public void rent() { System.out.println("我要租房子!"); } }
-
代理待租房子 有自己的一些方法
public class dali { private Host host; public dali(){} public dali(Host host) { this.host = host; } public void rent() { host.rent(); } }
-
客户端访问租房子
public class customer { @Test public void test() { Host host = new Host(); Dali dali = new Dali(host); dali.rent(); } }
静态代理的解决方法就是动态代理
输出一个日志 我们可以通过增加 代理的方式来实现 尽量的去增加东西 而不是删除东西
动态代理详解
动态代理运用的是反射这个技术
- 动态代理和静态代理的角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的!
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口— JDK动态代理 【我们在这里使用】
- 基于类: cglib
- java 字节码实现 : Javasist
需要了解两个类: Proxy : 代理 ,InvocationHandler:调用处理
InvocationHandler
动态代理的好处
- 可以使真实角色的操作更加的纯粹。不用去关心一些公共的事务
- 公共事务交给代理角色。实现了业务的分工
- 公共业务发生扩展时,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。
AOP
什么是AOP
导包
使用SpringAop的时候,我们必须得导包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
AOP的配置文件头
<?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"
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/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
AOP的实现流程
ApplicationContext 文件
<?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"
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/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.hai.spring.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.hai.spring.log.BeforeLog"/>
<bean id="afterLog" class="com.hai.spring.log.AfterLog"/>
<!--方式一 使用原生的Spring API 接口 -->
<!--配置AOP 需要导入aop 的约束 -->
<aop:config>
<!-- 切入点: expression 表达式 execution 要执行的位置! * * * * *-->
<aop:pointcut id="pointcut" expression="execution(* com.hai.spring.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加!-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
接口
package com.hai.spring.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
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("查询了一个用户!");
}
}
执行前
package com.hai.spring.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
// method: 要执行的目标对象的方法
// args: 参数
// target: 目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
执行后
package com.hai.spring.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() + "方法!");
}
}
AOP 实现方法二
方法二:使用自定义类来实现 AOP
自定义切入点 切入点中放通知
主要是切面定义
<bean id="diy" class="com.hai.spring.diy.DiyPointCut"/>
<aop:config>
<!-- 第一个星号代表反回值类型 第二个星号代表包-->
<!-- 自定义切面 ref 指的是要引用的类 -->
<aop:aspect ref="diy">
<!--切入点-->
// execution中放的是程序要执行的位置
<aop:pointcut id="pointcut" expression="execution(* com.hai.spring.service.UserServiceImpl.*(..))"/>
<!-- 通知 要执行的方法 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
package com.hai.spring.diy;
public class DiyPointCut {
public void before() {
System.out.println("========方法执行前==========");
}
public void after() {
System.out.println("========方法执行后==========");
}
}
test 测试类
public class TestOne {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
// 因为动态代理代理的是一个接口 不是一个类 所以我们要使用接口
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
}
注解实现AOP
<!-- 方式三-->
<bean id="annocationPointcut" class="com.hai.spring.diy.AnnocationPointcut"/>
<!-- 开启注解支持-->
<!-- 注解支持默认使用jdk-->
<aop:aspectj-autoproxy/>
@Aspect
public class AnnocationPointcut {
@Before("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("开始前!");
}
@After("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("开始后!");
}
@Around("execution(* com.hai.spring.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前!");
Object object = jp.proceed();
System.out.println("环绕后!");
}
}
回顾Mybatis
mybatis 核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 起别名 -->
<typeAliases>
<package name="com.hai.spring.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
<mappers>
<!-- <mapper resource="com/hai/mybatis/mapper/UserMapper.xml"/>-->
<!-- userMapper 和 xml文件的名字要相同 -->
<package name="com.hai.spring.mapper"/>
</mappers>
</configuration>
mappper配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hai.spring.mapper.UserMapper">
<resultMap id="UserMap" type="com.hai.spring.pojo.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
</resultMap>
<select id="getUser" resultMap="UserMap">
select * from mybatis.users
</select>
</mapper>
测试
package com.hai.test;
import com.hai.spring.mapper.UserMapper;
import com.hai.spring.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.List;
public class TestOne {
private SqlSession sqlSession;
private UserMapper userMapper;
@Before
public void before() throws IOException {
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession = factory.openSession();
}
@Test
public void getUser() {
userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.getUser();
for (User user : list) {
System.out.println("user = " + user );
}
}
@After
public void after() {
sqlSession.close();
}
}
Mybatis 与 Spring 整合
方法一
template 模板
整合数据源 SqlSessionFactory SqlSessionTemplat
<?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"
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/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- DataSource 数据源 使用Spring的数据源 替换 mybatis的配置
我们这里使用Spring 提供的数据源
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"/>
<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 配置文件 mybatis 资源的位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- mapper 的位置 -->
<property name="mapperLocations" value="classpath:com/hai/spring/mapper/*.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能使用构造器注入SqlSessionFactory 因为没有 set方法 创建sqlSessionFactory 对象 -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="userMapper" class="com.hai.spring.mapper.UserMapperImpl">
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
</beans>
创建实现类 实现mybatis 所作的工作
package com.hai.spring.mapper;
import com.hai.spring.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
/// 我们的所有操作 都将使用 SqlSessiontemplate 来做
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> getUser() {
UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
return userMapper.getUser();
}
}
测试实现类
package com.hai.test;
import com.hai.spring.mapper.UserMapper;
import com.hai.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class TestTwo {
@Test
public void test() {
// 通过application上下文拿到 spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationConText.xml");
UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
List<User> list = userMapper.getUser();
for (User user : list) {
System.out.println("user =" + user );
}
}
}
方法二:
package com.hai.spring.mapper;
import com.hai.spring.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperTwo extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> getUser() {
SqlSession sqlSession = getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
return userMapper.getUser();
}
}
<bean id="userMapper2" class="com.hai.spring.mapper.UserMapperTwo">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
方式二只需要配置 SqlSessionFactory 不需要配置别的
事务回顾
把一组事务当成一个事务来做,要么都成功 要么都失败
事务再项目开发中 十分的重要 涉及到数据的一致性问题 不能马虎
确保完整性和一致性
事务的ACID 原则
1. 原子性
2. 一致性
3. 隔离性: 多个事务之间互不干扰 为了保护数据
4. 持久性 事务一旦提交 无论系统发生什么事情 结果都不会被更改 被持久化的保存了
Spring声明式事务
七种配置事务的传播特性的方法
事务需要我们手动的在xml文件中配置
我们需要手动开启事务
配置切入点 在切入点中插入事务
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" 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"/>
<tx:method name="update"/>
<tx:method name="query"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入 就是配置 AOP 的操作 配置切入点 在切入点上配置上操作-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.hai.spring.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
总结
重点是理解思想
笔记持续完善