Spring

中文官网:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference

官方文档:https://docs.spring.io/spring-framework/docs/5.3.9-SNAPSHOT/reference/html/core.html#spring-core

IoC (Inversion of Control) 控制反转

AOP (Aspect Oriented Programming) 面向切面编程

1
2
3
4
5
6
<!-- maven依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.6</version>
</dependency>

IoC(可联想设计模式:工厂,装饰)

IoC是一种思想,将原本在程序中手动创建对象的控制权,交由Spring框架来管理,将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来,降低耦合性。原本我们是每需要一个功能就创建一个相应的对象,我们调用一个工厂(中间商),由它来创建对象,我们直接使用即可。就像设计模式中使用接口和抽象类,因为低耦合,这样我们在修改类时也会更方便,不会改一处导致其他地方都要变。

1.png

这里的齿轮图就很明显,原本的对象会互相限制,耦合性差,使用一个IoC容器管理后,每个对象相对于一个插件,然后我们再去修改对象就没有太多的限制了,不会影响很多其他对象。

AOP(动态代理:JDK和Cglib)

可参考:https://www.cnblogs.com/slivelove/p/10882195.html

AOP面向切面编程

运行时,动态的将代码切入到类的指定位置上的编程思想。如图,三个板块都需要一个验证用户的步骤,我们为什么不把这个步骤抽离出来,同时对应三个类来实现呢?所以在需要验证用户的地方切入一段验证的代码即可。其实就是把多个类中重复的部分抽取出来,当我们要使用它时再调用,不用每个都写。

切面:即切入到指定位置的代码片段,相对于一个

切点:而要切入的位置就是切点,即每个板块都要验证,但它们需要验证的地方可能不同,用切点来标记切入对应方法的位置

通知:切面在对应切点执行的操作,相对于方法,通知由多种形式,前置、后置、环绕、异常通知blog12.jpg

织入(Weaving),AOP术语。把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象,这样的行为叫做织入。


HelloSpring

bean文件的骨架

1
2
3
4
5
6
7
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

注册对象

1
2
3
4
5
6
7
8
<!--每个bean即一个对象
类型 变量名 = new 类型()
id = 变量名
class = new的对象
property = 对象赋值-->
<bean id="hello" class="com.tang.pojo.Hello">
<property name="str" value="Spring"/>
</bean>

测试(ApplicationContext)

1
2
3
4
5
6
7
8
9
public class MyTest {
public static void main(String[] args) {
//获得Spring的上下文对象,相关对象的配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//取出对应的对象,每次getBean都相当于new一个新对象
Hello hello = context.getBean("hello",Hello.class);
System.out.println(hello.toString());
}
}

IoC在这体现就是对象全权交由Spring管理

Spring配置

  • 别名

    1
    <alias name="user" alias="aaaaa"/>
  • Bean配置

    id:bean的唯一标识符,相对于变量名

    class:bean对象对应的全限定名,包名+类名

    name:别名

    1
    2
    3
    <bean id="user" class="com.tang.pojo.User" name="a,aaa,aa" >
    <property name="name" value="王刚"/>
    </bean>
  • import

    多用于项目开发,将其他人注册的内容导到一起使用,多合一

    1
    <import resource="applicationContext2.xml"/>
  • value是简单类型,如字符串直接赋值;ref复杂类型,设置对象属性


依赖注入(DI)

构造器注入

在加载配置文件时,容器中的对象已初始化

  • Spring默认使用无参构造器创建对象,如果写了有参但未声明无参,则会报错

    1
    2
    <!--默认使用无参-->
    <property name="name" value="王刚"/>
  • 自定义有参构造器,有参注入

    • index参数索引。参数在构造方法中对应的位置,0、1、2·····;且会调用对应的构造方法,如果只有一个有参构造方法,它有n个参数,我们必须把n个参数全部声明才可以。

      1
      <constructor-arg index="0" value="Spring1"/>
    • type参数类型

      1
      <constructor-arg type="java.lang.String" value="String2"/>
    • name参数名称

      1
      <constructor-arg name="name" value="Spring3"/>

Set方式注入(重点)

  • 依赖:bean对象的创建依赖于容器

  • 注入:bean对象的所有属性全由容器来注入(也就是使用对象?)

  • get、set方法,因为我们有很多种数据类型,所以对应的set方法注入有很多,但都差不多。

声明复杂对象:Address类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Address {
private String address;

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public String toString() {
return "Address{" +
"address=" + address +
'}';
}
}

实体类(一些测试的对象)

由于Address也是对象,我们自动生成的toString()要修改,给address也加上toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 Properties info;
private String TF;

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;
}

//get、set省略·····

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.toString() +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", games=" + games +
", info=" + info +
", TF='" + TF + '\'' +
'}';
}
}

容器(applicationContext.xml)

map和properties特殊一点,需要键值对应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="address" class="com.tang.pojo.Address">
<property name="address" value="武汉"/>
</bean>
<bean id="student" class="com.tang.pojo.Student">
<!-- 普通注入 -->
<property name="name" value="TC"/>

<!-- bean注入,注入一个类 -->
<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>avg</value>
<value>arpg</value>
<value>推理</value>
</list>
</property>

<!-- Map -->
<property name="card">
<map>
<entry key="身份证" value="11111"/>
<entry key="校园卡" value="180592010"/>
</map>
</property>

<!-- Set -->
<property name="games">
<set>
<value>game1</value>
<value>game2</value>
<value>game3</value>
</set>
</property>

<!-- null -->
<property name="TF">
<null/>
</property>

<!-- properties -->
<property name="info">
<props>
<prop key="a1">111</prop>
<prop key="a2">222</prop>
<prop key="a3">333</prop>
</props>
</property>
</bean>

</beans>

测试类

1
2
3
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());

特殊注入

c命名和p命名空间注入,可直接注入属性值,要导入xml约束

p对应无参构造器,c对应有参构造器

1
2
3
4
5
6
7
8
9
10
11
12
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="user" class="com.tang.pojo.User" p:name="TC" p:age="21"/>
<bean id="user2" class="com.tang.pojo.User" c:_0="TC" c:_1="18"/>

</beans>

bean的作用域

  • singleton(单例模式,也是Spring默认机制)

    显性配置在bean中添加scope=”singleton”即可

    即每次使用bean创建都是共享同一个对象

  • prototype(原型模式)

    每次bean创建都是一个新对象

  • request、session、application、websocket

    这些都是在web开发中使用


bean的自动装配

IoC容器装配一般有三种方式:xml显示配置,在java中显示配置,bean隐式配置自动装配

1
2
3
4
5
6
7
8
9
10
11
12
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="cat" class="com.tang.pojo.Cat"/>
<bean id="dog" class="com.tang.pojo.Dog"/>
<bean id="people" class="com.tang.pojo.People" autowire="byName">
<property name="name" value="TC"/>
</bean>
</beans>

使用autowire配置

  • byName(id唯一) id应与set方法的属性名一致
  • byType(class唯一) 若两个声明均使用同一个类会报错的

注解自动装配

使用注解的模板,相关约束

1
2
3
4
5
6
7
8
9
10
11
12
<?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>

@Autowired(Spring提供)

在定义属性时使用,或set方法上使用。通过byType实现自动装配,有多个会识别id也就是byName

Autowired还有required属性,可自行T、F指定是否使用自动装配

1
2
3
4
@Autowired
private Cat cat;
@Autowired
public void setDog(Dog dog) { this.dog = dog; }

@Qualifier(value = “xxx”)

和@Autowired配套使用,如果bean中有多个同类型的配置,autowire是无法识别的,可以用@Qualifier来指定要使用的对象,value填入对应的id即可

@Resource(J2EE提供)

和Autowired不同,该注解先通过byName实现自动装配,如果不行则使用byType,都不行则报错

@Nullable

被标记的字段可为空


注解开发

首先一定要导入相关的约束

还要导入aop的包(导入webmvc会自动导入)

1
2
3
4
5
6
7
8
9
10
11
12
<?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>

属性注入

  • @Component(组件描述)

    1
    <bean id="user" class="com.tang.pojo.User"/>
  • @Value(注解赋值)

    1
    <property name="name" value="TC"/>
1
2
3
4
5
@Component
public class User {
@Value("TC")
public String name;
}

衍生注解

  • dao层:@Repository

  • service层:@Service

  • controller层:@Controller

  • 在其他组件上添加注解时使用:@Component

这四个注解功能一致,将类注册到容器中,只是区分用于不同层、不同类

自动装配

前面记录了

  • @Autowired
  • @Qualifier
  • @Resource
  • @Nullable

作用域

  • @Scope()

singleton、prototype等等,直接填写作用域对应参数即可


使用Java配制Spring

Spring Boot出现后便广泛使用

1
2
3
4
5
6
7
8
@Configuration
@ComponentScan(basePackages = "com.tang.pojo")
public class Config {
@Bean
public User Hello(){
return new User();
}
}
  • @Configuration

    给javaConfig配置类加上该注解,相对于applicationContext.xml

  • @Bean

    在注解的javaConfig配置类中,给方法添加该注解相对于注册bean

    @Bean(“ttt”),bean的id默认为注解方法的方法名,可在括号里自行配置id

    return返回值即bean中配置的class

  • @Import()

    导入其他配置

测试(AnnotationConfigApplicationContext)

1
2
3
4
5
6
7
public class MyTest {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
User hello = context.getBean("Hello", User.class);
System.out.println(hello.Hello("TTT"));
}
}

AOP实现

使用AOP织入的相关依赖

1
2
3
4
5
6
7
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>

aop相关约束

1
2
3
4
5
6
7
8
9
10
<?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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

</beans>

定义接口,创建实现类

1
2
3
4
5
6
public interface UserService {
public void add();
public void update();
public void delete();
public void select();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增");
}

public void update() {
System.out.println("改");
}

public void delete() {
System.out.println("删");
}

public void select() {
System.out.println("查");
}
}

方式一:使用Spring的API接口(注意看测试类!!)

前置通知

1
2
3
4
5
6
7
8
9
10
/**
* method:要执行目标对象的方法
* args:参数列表
* target:执行方法所属类的目标对象
*/
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}

后置通知(returValue返回值)

1
2
3
4
5
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回值为"+returnValue);
}
}

注册bean及aop实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<bean id="userService" class="com.tang.service.UserServiceImpl"/>
<bean id="log" class="com.tang.log.Log"/>
<bean id="afterLog" class="com.tang.log.AfterLog"/>
<!-- 方式一:使用原生Spring API接口-->
<aop:config>
<!--
切入点,在哪里执行方法
expression表达式固定写法 execution(* * * * *)
*依次代表:返回值、包、类、方法、参数
-->
<aop:pointcut id="pointcut" expression="execution(* com.tang.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加 -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

</beans>

测试(注意!!)

此处应该转为接口类型,即向上转型,因为是动态代理,可以有很多个不同的实现类,但为了统一,我们不用明确使用的是哪一个实现类,直接转换成其接口类型即可,毕竟都可以统一成接口类型,这样怎样实现都和我们的操作没有关系,只用改xml的bean的对应实现类即可。

1
2
3
4
5
6
7
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意动态代理的是接口,不是实现类,向上转型的理念
UserService userService = (UserService) context.getBean("userService");
userService.add();
}

方法二:自定义类实现

diy类

1
2
3
4
5
6
7
8
9
public class DiyPoint {
public void before(){
System.out.println("===方法执行前===");
}

public void after(){
System.out.println("===方法执行后===");
}
}

aop配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<bean id="userService" class="com.tang.service.UserServiceImpl"/>
<bean id="log" class="com.tang.log.Log"/>
<bean id="afterLog" class="com.tang.log.AfterLog"/>

<!-- 方式二:自定义类 -->
<bean id="diy" class="com.tang.diy.DiyPoint"/>

<aop:config>
<!-- 自定义切面,ref即要引用的类-->
<aop:aspect ref="diy">
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* com.tang.service.UserServiceImpl.*(..))"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>xml
</aop:aspect>
</aop:config>

</beans>

方式三:注解实现

注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//切面
@Aspect
public class annotate {

@Before("execution(* com.tang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前111");
}

@After("execution(* com.tang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后222");
}

//在环绕通知中,可给定参数,代表我们要获取处理切入点--连接点
// @Around("execution(* com.tang.service.UserServiceImpl.*(..))")
// public void around(ProceedingJoinPoint jp) throws Throwable {
// System.out.println("环绕前");
// //模拟执行
// Object proceed = jp.proceed();
// System.out.println("环绕后");
// }
}

aop配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<bean id="userService" class="com.tang.service.UserServiceImpl"/>
<bean id="log" class="com.tang.log.Log"/>
<bean id="afterLog" class="com.tang.log.AfterLog"/>

<!-- 方式三:注解 -->
<bean id="annotate" class="com.tang.annotate.annotate"/>
<!-- 开启注解支持 默认JDK(proxy-target-class="false") Cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy/>

</beans>

整合MyBatis

MyBatis流程复习

导入相关jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?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">
<parent>
<artifactId>Spring</artifactId>
<groupId>com.tang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-08-mybatis</artifactId>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
</dependencies>

</project>
  • 编写实体类
  • 编写核心配置文件
  • 编写接口Mapper
  • 编写接口对应的Mapper.xml
  • 测试类

MyBatis-Spring

SqlSessionTemplate

官网:http://mybatis.org/spring/zh/index.html

编写数据源 & sqlSessionFactory & sqlSessionTemplate(就是以前的sqlSession)

spring-dao.xml就负责所有的配置,其中sqlSessionTemplate通过构造器注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<!-- DataSource:使用Spring数据源替换MyBatis的配置 c3p0 dbcp
使用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&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</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/tang/mapper/*.xml"/>
</bean>

<!-- SqlSessionTemplate即sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 使用构造器注入,因为没有set方法 -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>

为接口添加实现类

1
2
3
4
5
6
7
8
9
10
11
12
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();
}
}

将实现类注入到Spring,并测试

  • applicationContext.xml

    导入相关配置文件,并注入实现类,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?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:aop = "http://www.springframework.org/schema/aop"
    xsi:schemaLocation = "http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

    <import resource="spring-dao.xml"/>

    <!-- 获取相应对象,进行操作 -->
    <bean id="UserMapper" class="com.tang.mapper.UserMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
    </bean>
    </beans>
  • 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void test(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("UserMapper", UserMapper.class);
    for(User user : userMapper.selectUser())
    System.out.println(user);
    }

SqlSessionDaoSupport(和SqlSessionTemplate比较)

接口实现类

1
2
3
4
5
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}

applicationContext注入bean

1
2
3
<bean id="userMapper2" class="com.tang.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

使用SqlSessionDaoSupport,则spring-dao的配置文件中就不用配置SqlSessionTemplate(sqlSession)


声明式事务

http://mybatis.org/spring/zh/transactions.html

事务应确保一致性和完整性;将一组业务当作一个业务来做,要么都成功,要么都失败。

ACID:原子性、一致性、隔离性、持久性

  • Spring中事务管理
    • 声明式事务:AOP
    • 编程式事务:要在代码中,进行事务管理

sql语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;

public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}

public int addUser(User user) {
return sqlSession.getMapper(UserMapper.class).addUser(user);
}

public int deleteUser(int id) {
return sqlSession.getMapper(UserMapper.class).deleteUser(id);
}

public List<User> selectUser() {
User user = new User(7, "777", "88");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(1);
return mapper.selectUser();
}
}

在spring-dao中配置事务及aop切入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 结合AOP实现事务织入,配置事务的类-->
<tx:advice id="advice" transaction-manager="transactionManager">
<!-- 选择要配置事务的方法 -->
<!-- 配置事务的传播特性-->
<tx:attributes>
<tx:method name="addUser" propagation="REQUIRED"/>
<tx:method name="deleteUser"/>
<tx:method name="selectUser"/>
</tx:attributes>
</tx:advice>

<!-- 配置事务切入:AOP-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.tang.mapper.*.*(..))"/>
<aop:advisor advice-ref="advice" pointcut-ref="txPointcut"/>
</aop:config>

我们把多个sql语句整合到一起执行(添加、删除、查询),若其中删除出现错误但添加是正确的,我们会发现数据库仍然执行了添加语句。

若我们添加事务tx及配置aop切入的地方,我们会发现整个sql语句会变成整体,即使添加语句是对的,但删除语句错误会导致回滚。我们完全实现了事务。


小结

学的时候还是多用xml文件来配置,之后会对注解开发多熟悉一下,然后就是Spring MVC赶紧!