【Spring学习笔记 八】Spring整合MyBatis实现方式(下)

简介: 【Spring学习笔记 八】Spring整合MyBatis实现方式(下)

Spring的实现回顾

当然我们还需要配置相关Spring的内容,例如我们通过Service来控制Dao层的实现,并且在调用方法前后增加切面控制增加访问日志:

1 创建Service层

创建PersonService及其实现类

PersonService

package com.example.spring_mybatis.service;
import com.example.spring_mybatis.model.Person;
import java.util.List;
public interface PersonService {
    List<Person> getPersonList();
}

PersonService

package com.example.spring_mybatis.serviceImpl;
import com.example.spring_mybatis.daoImpl.PersonDaoImpl;
import com.example.spring_mybatis.model.Person;
import com.example.spring_mybatis.service.PersonService;
import lombok.Data;
import java.util.List;
@Data
public class PersonServiceImpl implements PersonService {
    private PersonDaoImpl personDaoImpl;
    @Override
    public List<Person> getPersonList() {
        return personDaoImpl.getPersonList();
    }
}

2 创建Dao层

Dao层的接口我们已经在MyBatis部分实现了,接下来只要编写其实现类即可:

package com.example.spring_mybatis.daoImpl;
import com.example.spring_mybatis.dao.PersonDao;
import com.example.spring_mybatis.model.Person;
import java.util.List;
public class PersonDaoImpl implements PersonDao {
    @Override
    public List<Person> getPersonList() {
        return null;
    }
}

这里我们先不编写其实现,这里的实现其实就是我们今天的主题。

3 增加AOP类

增加Aop类关于日志的,扫描service包,给这个包里的方法前后都加日志:

package com.example.spring_mybatis.aop;
import java.time.LocalDateTime;
/**
 * * @Name LogProxy
 * * @Description
 * * @author tianmaolin
 * * @Data 2021/8/24
 */
public class LogAop  {
    public void beforeLog()  {
        System.out.println("日志记录开始"+ LocalDateTime.now());
    }
    public void afterLog()  {
        System.out.println("日志记录结束"+ LocalDateTime.now().plusMinutes(5));
    }
}

4 applicationContext.xml配置文件编写

我们先编写目前用到的一些配置,包括Service对Dao的调用:

<?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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 使用aop注解 -->
    <aop:aspectj-autoproxy/>
    <!-- 定义目标对象:定义被代理者 -->
    <bean id="personServiceImpl" class="com.example.spring_mybatis.serviceImpl.PersonServiceImpl">
        <property name="personDaoImpl" ref="personDaoImpl"/>
    </bean>
    <bean id="personDaoImpl" class="com.example.spring_mybatis.daoImpl.PersonDaoImpl">
    </bean>
    <!-- 定义切面,切面内包含通知要执行的方法-->
    <bean id="logAop" class="com.example.spring_mybatis.aop.LogAop"></bean>
    <!--aop的配置-->
    <aop:config proxy-target-class="true">
        <!--切面配置-->
        <aop:aspect ref="logAop">
            <!--切点-->
            <aop:pointcut id="logPointCut" expression="execution(* com.example.spring_mybatis.service..*.*(..))"/>
            <!--切点-通知-->
            <aop:before pointcut-ref="logPointCut" method="beforeLog"/>
            <aop:after pointcut-ref="logPointCut" method="afterLog"/>
        </aop:aspect>
    </aop:config>
</beans>

Spring整合MyBatis

Spring整合用到一个依赖,也就是我们上述坐标中的,其官方文档介绍:mybatis-spring

<!-- Mybatis-Spring相关 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>

什么是 MyBatis-Spring?MyBatis-Spring 会帮助我们将 MyBatis 代码无缝地整合到 Spring 中。Spring整合MyBatis, 主要目的就是把MyBatis核心配置文件及Mapper文件中的内容交给Spring来处理,通俗的说,就是Spring把SqlSession的创建以及Mapper对象的创建都代理了,事实上就是我们不用再编写相关的配置文件以及配置文件读取类了,也就是我们上述的8个步骤中4-6步都不用做了,Spring完全代工。

1 SqlSession注入实现

那么首先来看第一种方式,我们通过这种方式可以干掉mybatis-config.xml,完全通过Spring来实现.

1-1 调整配置文件applicationContext.xml

由Spring来构建SqlSession,同时MybatisUtil也不需要了,SqlSession的构建完全交给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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 使用aop注解 -->
    <aop:aspectj-autoproxy/>
    <!-- 定义目标对象:定义被代理者 -->
    <bean id="personServiceImpl" class="com.example.spring_mybatis.serviceImpl.PersonServiceImpl">
        <property name="personDaoImpl" ref="personDaoImpl"/>
    </bean>
    <bean id="personDaoImpl" class="com.example.spring_mybatis.daoImpl.PersonDaoImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
    <!--DataSource: 使用Spring的数据源替换Mybatis的配置, 可以使用c3p0,dbcp,druid,或者spring提供的jdbc-->
    <!-- 加载数据库配置信息 -->
    <context:property-placeholder location="properties/db.properties" system-properties-mode="NEVER"/>
    <!-- 连接池对象 -->
    <bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--配置日志输出-->
    <bean id="configuration" class="org.apache.ibatis.session.Configuration">
        <property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
    </bean>
    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <!--关联Mybatis-->
        <!--<property name="configLocation" value="mybatis-config.xml"/>-->
        <property name="mapperLocations" value="mappers/*.xml"/>
        <property name="configuration" ref="configuration"/>
    </bean>
    <!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能通过构造器注入sqlSessionFactory,因为没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <!-- 加载日志配置信息 -->
    <context:property-placeholder location="log4j.properties" system-properties-mode="NEVER"/>
    <!-- 定义切面,切面内包含通知要执行的方法-->
    <bean id="logAop" class="com.example.spring_mybatis.aop.LogAop"></bean>
    <!--aop的配置-->
    <aop:config proxy-target-class="true">
        <!--切面配置-->
        <aop:aspect ref="logAop">
            <!--切点-->
            <aop:pointcut id="logPointCut" expression="execution(* com.example.spring_mybatis.service..*.*(..))"/>
            <!--切点-通知-->
            <aop:before pointcut-ref="logPointCut" method="beforeLog"/>
            <aop:after pointcut-ref="logPointCut" method="afterLog"/>
        </aop:aspect>
    </aop:config>
</beans>

上述配置中我们用到了这几个概念:

  • 在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory ,而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建
  • SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替代码中已经在使用的 SqlSession

也就是原生Mybatis的SqlSession获取过程被Spring给接管了。

1-2 调整PersonDaoImpl类实现

由上边的配置我们发现,SqlSession被构建好后注入到了PersonDaoImpl中,这样实现类就可以打开一个session并执行相关逻辑了,然后具体的实现使用SqlSession通过personMapper.xml配置文件去构建代理对象然后调用方法实现。

package com.example.spring_mybatis.daoImpl;
import com.example.spring_mybatis.dao.PersonDao;
import com.example.spring_mybatis.model.Person;
import lombok.Data;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
@Data
public class PersonDaoImpl implements PersonDao {
    private SqlSessionTemplate sqlSession;
    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }
    @Override
    public List<Person> getPersonList() {
        return  sqlSession.getMapper(PersonDao.class).getPersonList();
    }
}

1-3 测试实现方式

最后我们来编写个单元测试类来测试下实现过程:

import com.example.spring_mybatis.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonServiceTest {
    @Test
    public void getPersonListTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonService personService = (PersonService) applicationContext.getBean("personServiceImpl");
        personService.getPersonList();
    }
}

打印结果如下:

2 SqlSessionFactory注入实现

让Dao继承Support类 , 直接利用 getSqlSession()获得SqlSessionTemplate , 然后直接注入SqlSessionFactory . 比起方式1 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好

再向下追溯,可以发现SqlSessionTemplate有属性sqlSessionFactory,所以按照依赖链正常注入使用:

2-1 调整配置文件applicationContext.xml

我们调整配置文件,让SqlSessionFactory直接注入到PersonDaoImpl,不再使用中间的SqlSessionTemplate作为媒介:

<?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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 使用aop注解 -->
    <aop:aspectj-autoproxy/>
    <!-- 定义目标对象:定义被代理者 -->
    <bean id="personServiceImpl" class="com.example.spring_mybatis.serviceImpl.PersonServiceImpl">
        <property name="personDaoImpl" ref="personDaoImpl"/>
    </bean>
    <bean id="personDaoImpl" class="com.example.spring_mybatis.daoImpl.PersonDaoImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
    <!--DataSource: 使用Spring的数据源替换Mybatis的配置, 可以使用c3p0,dbcp,druid,或者spring提供的jdbc-->
    <!-- 加载数据库配置信息 -->
    <context:property-placeholder location="properties/db.properties" system-properties-mode="NEVER"/>
    <!-- 连接池对象 -->
    <bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--配置日志输出-->
    <bean id="configuration" class="org.apache.ibatis.session.Configuration">
        <property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
    </bean>
    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <!--关联Mybatis-->
        <!--<property name="configLocation" value="mybatis-config.xml"/>-->
        <property name="mapperLocations" value="mappers/*.xml"/>
        <property name="configuration" ref="configuration"/>
    </bean>
    <!-- 加载日志配置信息 -->
    <context:property-placeholder location="log4j.properties" system-properties-mode="NEVER"/>
    <!-- 定义切面,切面内包含通知要执行的方法-->
    <bean id="logAop" class="com.example.spring_mybatis.aop.LogAop"></bean>
    <!--aop的配置-->
    <aop:config proxy-target-class="true">
        <!--切面配置-->
        <aop:aspect ref="logAop">
            <!--切点-->
            <aop:pointcut id="logPointCut" expression="execution(* com.example.spring_mybatis.service..*.*(..))"/>
            <!--切点-通知-->
            <aop:before pointcut-ref="logPointCut" method="beforeLog"/>
            <aop:after pointcut-ref="logPointCut" method="afterLog"/>
        </aop:aspect>
    </aop:config>
</beans>

2-2 调整PersonDaoImpl类实现

当然相应的也要调整PersonDaoImpl类的实现方式:

package com.example.spring_mybatis.daoImpl;
import com.example.spring_mybatis.dao.PersonDao;
import com.example.spring_mybatis.model.Person;
import lombok.Data;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
@Data
public class PersonDaoImpl extends SqlSessionDaoSupport implements PersonDao {
    @Override
    public List<Person> getPersonList() {
        return  getSqlSession().getMapper(PersonDao.class).getPersonList();
    }
}

2-3 测试实现方式

测试类还使用之前的:

import com.example.spring_mybatis.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonServiceTest {
    @Test
    public void getPersonListTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonService personService = (PersonService) applicationContext.getBean("personServiceImpl");
        personService.getPersonList();
    }
}

可以看到打印结果同上:

3 Mapper对象自动扫描注入实现

前两种的整合实现方式都创建了Dao接口的实现类,通过SqlSession来获取mapper对象。使用第三种方式我们可以告诉Spring让其帮我们自动创建mapper的代理对象,也就是我们不再需要PersonDaoImpl了,它也由Spring代为生成:

3-1 调整配置文件applicationContext.xml

我们调整配置文件,干掉personDaoImpl的相关配置,直接使用映射类生成器生成:

<?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"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 使用aop注解 -->
    <aop:aspectj-autoproxy/>
    <!-- 定义目标对象:定义被代理者 -->
    <bean id="personServiceImpl" class="com.example.spring_mybatis.serviceImpl.PersonServiceImpl">
        <property name="userMapper" ref="userMapper"/>
    </bean>
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!--给哪个接口创建代理对象-->
        <property name="mapperInterface" value="com.example.spring_mybatis.dao.PersonDao"/>
    </bean>
    <!--DataSource: 使用Spring的数据源替换Mybatis的配置, 可以使用c3p0,dbcp,druid,或者spring提供的jdbc-->
    <!-- 加载数据库配置信息 -->
    <context:property-placeholder location="properties/db.properties" system-properties-mode="NEVER"/>
    <!-- 连接池对象 -->
    <bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--配置日志输出-->
    <bean id="configuration" class="org.apache.ibatis.session.Configuration">
        <property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
    </bean>
    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <!--关联Mybatis-->
        <!--<property name="configLocation" value="mybatis-config.xml"/>-->
        <property name="mapperLocations" value="mappers/*.xml"/>
        <property name="configuration" ref="configuration"/>
    </bean>
    <!-- 加载日志配置信息 -->
    <context:property-placeholder location="log4j.properties" system-properties-mode="NEVER"/>
    <!-- 定义切面,切面内包含通知要执行的方法-->
    <bean id="logAop" class="com.example.spring_mybatis.aop.LogAop"></bean>
    <!--aop的配置-->
    <aop:config proxy-target-class="true">
        <!--切面配置-->
        <aop:aspect ref="logAop">
            <!--切点-->
            <aop:pointcut id="logPointCut" expression="execution(* com.example.spring_mybatis.service..*.*(..))"/>
            <!--切点-通知-->
            <aop:before pointcut-ref="logPointCut" method="beforeLog"/>
            <aop:after pointcut-ref="logPointCut" method="afterLog"/>
        </aop:aspect>
    </aop:config>
</beans>

3-2 调整PersonServiceImpl类实现

同时我们需要在PersonServiceImpl中替换方法的实现方式,使用我们自动生成的userMapper,而不是对应创建的:

package com.example.spring_mybatis.serviceImpl;
import com.example.spring_mybatis.dao.PersonDao;
import com.example.spring_mybatis.daoImpl.PersonDaoImpl;
import com.example.spring_mybatis.model.Person;
import com.example.spring_mybatis.service.PersonService;
import lombok.Data;
import java.util.List;
@Data
public class PersonServiceImpl implements PersonService {
    private PersonDao userMapper;
    @Override
    public List<Person> getPersonList() {
        List<Person> personList=userMapper.getPersonList();
        for (Person person : personList) {
            System.out.println(person);
        }
        return personList;
    }
}

3-3 测试实现方式

测试类还使用之前的:

import com.example.spring_mybatis.service.PersonService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonServiceTest {
    @Test
    public void getPersonListTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonService personService = (PersonService) applicationContext.getBean("personServiceImpl");
        personService.getPersonList();
    }
}

打印结果如下:

总结一下

完成了上述的实现方式之后,我们确定最终的项目整体结构如下:

本篇Blog讨论了三种Spring整合MyBatis的方式,随着实现方式的递进,我们越来越多的工作交给了Spring去做,第一种整合方式我们配置了sqlSessionFactory(myDataSource,configuration),sqlSession,然后把sqlSession注入personDaoImpl类,通过这个步骤,我们摆脱了mybatis-config.xml核心配置文件的编写、MybatisUtils辅助类的编写。第二种整合方式我们抛弃了sqlSession,直接用sqlSessionFactory注入personDaoImpl实现。第三种整合方式我们则干脆抛弃了实现类personDaoImpl的编写,实现类的生成由Spring控制,其实继续演化下去,我们连mapper配置文件都可以抛弃,那就是使用注解,这些内容在Spring Boot中体现吧,所以框架就是先给出配置规则,再持续简化,让程序员逐渐变成傻瓜,俗称傻瓜式编程,但是如果原理不知道,出了错误可就不好排查了,所以我们还是不要做傻瓜好了。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
28天前
|
算法 Java 数据库连接
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
|
1天前
|
安全 Java 数据库连接
Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速开发平台项目
Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速开发平台项目
12 0
|
9天前
|
Java 数据库连接 数据库
Spring日志完结篇,MyBatis操作数据库(入门)
Spring日志完结篇,MyBatis操作数据库(入门)
|
21天前
|
Java 关系型数据库 数据库连接
MyBatis-Plus介绍及Spring Boot 3集成指南
MyBatis-Plus是一个MyBatis扩展工具,旨在简化Java开发中的CRUD操作。它具有无侵入性、低损耗、强大的CRUD功能、Lambda表达式支持、主键自动生成、ActiveRecord模式、全局操作和内置代码生成器等特点。在Spring Boot 3中集成MyBatis-Plus,需在pom.xml添加依赖,排除特定版本的mybatis-spring,并用@MapperScan注解指定Mapper接口路径。此外,还介绍了如何使用MyBatis-Plus代码生成器自动生成Mapper、Model、Service和Controller层代码,以加速开发。
64 2
MyBatis-Plus介绍及Spring Boot 3集成指南
|
21天前
|
Java 关系型数据库 MySQL
SpringBoot整合JUnit、MyBatis、SSM
SpringBoot整合JUnit、MyBatis、SSM
28 4
|
21天前
|
Java 数据库连接 数据库
Spring整合Mybatis、Spring整合JUnit
Spring整合Mybatis、Spring整合JUnit
25 1
Spring整合Mybatis、Spring整合JUnit
|
23天前
|
Java 数据库连接 数据库
小唐开始学 Spring Boot——(3)利用mybatis访问数据表
小唐开始学 Spring Boot——(3)利用mybatis访问数据表
|
1月前
|
JSON Java 数据格式
nbcio-boot升级springboot、mybatis-plus和JSQLParser后的LocalDateTime日期json问题
nbcio-boot升级springboot、mybatis-plus和JSQLParser后的LocalDateTime日期json问题
21 0
|
1月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
213 1
|
1月前
|
Java 数据库连接 Spring
Spring 整合mybatis
Spring 整合mybatis
26 2