环境搭建 EvBuild


 

软件环境准备

-  MySQL 5.0 +

-  IDEA 2018 +

-  JDK1.8 +

依赖包相关

-  Junit单元测试

-  JDBC驱动

-  Mybatis 组件

-  Spring组件

-  AopWeaver切面织入包

-  Mybatis-Spring【MS专用整合包】

-  Lombok

-  Log4J 日志输出

 


 

官方文档:

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

 

什么是 MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。

它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,

以及将 Mybatis 的异常转换为 Spring 的 DataAccessException

最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。

 

使用须知:

使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。

这很重要——因为本手册中不会提供二者的基本内容,安装和配置教程。

MyBatis-Spring 需要以下版本:

 

MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

 


工程创建

在前面的Spring工程基础上创建新模块

【Mybatis + Spring】 Mybatis - Spring 结合_sql

 

开始配置Maven依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.6.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.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

 

 

资源过滤问题

<!--在build中配置resources,来防止我们资源导出失败的问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>

            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

回顾原生Mybatis开发步骤:

1、编写实体类

2、Mybatis-Config.xml核心配置文件

3、Dao接口,或者说Mapper接口

4、编写Mapper.xml映射器配置、注册映射器

5、测试

 

实体类POJO

package cn.dai.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer user_id;
    private String user_name;
    private String user_password;
}

 

Mybatis-Config.xml

<?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>

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <typeAliases>
        <package name="cn.dai.pojo"/>
    </typeAliases>

    <environments default="dev1">

        <environment id="dev1">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

 

Mapper.xml

很多人不喜欢映射器文件和接口放在一起,并且Maven也确实存在资源过滤问题

这样,我们可以放在资源目录下,新建一个mappers目录,统一放在这里面

【Mybatis + Spring】 Mybatis - Spring 结合_xml_02

编写映射器UserMapper.xml

<?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="cn.dai.mapper.UserMapper">

    <select id="getAllUserList" resultType="user">
        SELECT * FROM user;
    </select>
    
</mapper>

 

在核心配置中这样注册映射器

<mappers>
  <mapper resource="mappers/UserMapper.xml"/>
</mappers>

 

MybatisUtil.java

我们自己配置的会话获取工具类

public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    
    static {
        String mybatis_config = "Mybatis-Config.xml";

        try {
            InputStream inputStream = Resources.getResourceAsStream(mybatis_config);

            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

            sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            
            sqlSessionFactoryBuilder = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(boolean closeTransaction) {
        return sqlSessionFactory.openSession(closeTransaction);
    }
}

 

配置LOG4J日志输出【可选】

如果不要配置,把Mybatis-Config.xml的Settings删除

编写log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/l4j.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

 

在测试类加入日志实例

org.apache.log4j.Logger;
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MybatisTest.class);

 

测试Mybatis环境搭建是否正常

public class MybatisTest {

    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MybatisTest.class);

    @Test
    public void sqlTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> allUserList = mapper.getAllUserList();

        for (User user:allUserList){
            logger.info(user);
        }

        sqlSession.close();
    }
}

 


 

开始整合 Start Integration

现在我们把对象交给Spring管理,

再也不需要我们自己编写的MybatisUtil会话获取工具类了

编写Spring的Bean容器配置文件

<?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"

       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

       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd

       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
"
>
    <context:annotation-config />
    <context:component-scan base-package="cn.dai" />
    <aop:aspectj-autoproxy proxy-target-class="false"/>


</beans>

 

快速上手

要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:

一个 SqlSessionFactory 和至少一个数据映射器类。

在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean来创建 SqlSessionFactory

要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

或者使用纯JavaConfig的注解方式

@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
  SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
  factoryBean.setDataSource(dataSource());
  return factoryBean.getObject();
}

注意:SqlSessionFactory 需要一个 DataSource(数据源)。

这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。

 

【在狂神的是XML配置,上面的会话工厂Bean需要引用一个数据源实例,它采用的是Spring提供的数据源】

<!-- 我们所学过的连接池【数据源】有C3P0、DRUID、HIKARI、DBCP、 -->
    <!-- 这里使用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:///mybatis?serverTimezone=GMT" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>

可以看看这个数据源类的源码是怎样的?

源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.jdbc.datasource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

public class DriverManagerDataSource extends AbstractDriverBasedDataSource {
    public DriverManagerDataSource() {
    }

    public DriverManagerDataSource(String url) {
        this.setUrl(url);
    }

    public DriverManagerDataSource(String url, String username, String password) {
        this.setUrl(url);
        this.setUsername(username);
        this.setPassword(password);
    }

    public DriverManagerDataSource(String url, Properties conProps) {
        this.setUrl(url);
        this.setConnectionProperties(conProps);
    }

    public void setDriverClassName(String driverClassName) {
        Assert.hasText(driverClassName, "Property 'driverClassName' must not be empty");
        String driverClassNameToUse = driverClassName.trim();

        try {
            Class.forName(driverClassNameToUse, true, ClassUtils.getDefaultClassLoader());
        } catch (ClassNotFoundException var4) {
            throw new IllegalStateException("Could not load JDBC driver class [" + driverClassNameToUse + "]", var4);
        }

        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Loaded JDBC driver: " + driverClassNameToUse);
        }

    }

    protected Connection getConnectionFromDriver(Properties props) throws SQLException {
        String url = this.getUrl();
        Assert.state(url != null, "'url' not set");
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Creating new JDBC DriverManager Connection to [" + url + "]");
        }

        return this.getConnectionFromDriverManager(url, props);
    }

    protected Connection getConnectionFromDriverManager(String url, Properties props) throws SQLException {
        return DriverManager.getConnection(url, props);
    }
}

 

所以,在Mybatis-Config.xml的环境配置就可以舍弃了

Mybatis-Config.xml可以删除的部分

<environments default="dev1">

        <environment id="dev1">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

 

连接参数的读取就可以让Spring的ApplicationContext读取了

接着,Mybatis-Config.xml这个核心配置文件又

可以让会话工厂实例的configuration属性读取

<!-- SQL会话工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configuration" value="classpath:Mybatis-Config.xml" />
    </bean>

其实这个会话工厂实例Bean的设置完全涵盖了核心配置

【狂神推荐 别名 & 设置 留给 Mybatis-Config.xml 核心配置,其他部分完全Spring容器接管】

注意映射器的配置只能保存一个,在Spring写了就不能再在Mybatis-Config.xml保留

<!-- SQL会话工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源 连接池-->
        <property name="dataSource" ref="dataSource" />
        <!-- 核心配置地址 -->
        <property name="configLocation" value="classpath:Mybatis-Config.xml" />
        <!-- 配置映射器位置-->
        <property name="mapperLocations" value="classpath:mappers/UserMapper.xml"/>
    </bean>

 

然后是SqlSession的Bean注册

    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只允许构造器注入 没有setSqlSession方法 -->
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

 

但是在Mapper包,我们就需要多写一个实现类

public class UserMapperImpl implements UserMapper{
    
    // 现在使用SqlSessionTemplate完成
    SqlSessionTemplate sqlSession;

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

    public List<User> getAllUserList() {
        return sqlSession.getMapper(UserMapper.class).getAllUserList();
    }
}

 

Bean注册

<bean id="userMapperImpl" class="cn.dai.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSessionTemplate" />
    </bean>

 

测试

import cn.dai.mapper.UserMapper;
import cn.dai.pojo.User;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class MybatisSpringIntegration {

    private static Logger logger = Logger.getLogger(MybatisSpringIntegration.class);

    @Test
    public void msTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Canned.xml");
        UserMapper userMapper = applicationContext.getBean("userMapperImpl", UserMapper.class);

        List<User> allUserList = userMapper.getAllUserList();

        for (User user:allUserList){
            logger.info(user);
        }

    }
}

整合总结:

1、数据库数据准备

2、实体类编写,暂不需要Bean注册

3、编写Mybatis-Config.xml配置,也可以让Spring全权Bean化处理

4、编写Mapper接口,SQL的抽象方法

5、编写Mapper.xml映射器配置,可以放在接口包,也可以是资源目录

6、Mapper的注册交给Mybatis-Config.xml或者是Bean处理

7、LOG4J日志输出配置【可选】

8、配置Spring容器类

9、配置数据源【DataSource 连接池】Bean化

10、配置SQL会话工厂【SqlSessionFactory】Bean化

11、SQL会话工厂可以完全配置Mybatis-Config.xml【可选,自己看情况设置】

12、配置SQL会话模板【SqlSessionTemplate】Bean化

13、编写XXXmapper实现类,同时配置Bean

14、测试,或者实际使用,从ApplicationContext获取即可


第二种整合方式: 

只是在上面的基础上有一点改动

官方在我们编写实现类要组合SqlSessionTemplate的这个步骤上封装了

我们只需要继承SqlSessionDaoSupport类即可

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {

    public List<User> getAllUserList() {
        return this.getSqlSession().getMapper(UserMapper.class).getAllUserList();
    }
}

 

在Bean的配置上,只需要注入SQL会话工厂即可

<bean id="userMapperImpl2" class="cn.dai.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

 

测试

    @Test
    public void msTest2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Canned.xml");
        UserMapper userMapper = applicationContext.getBean("userMapperImpl2", UserMapper.class);
        List<User> allUserList = userMapper.getAllUserList();
        for (User user:allUserList){
            logger.info(user);
        }
    }

 


 

关于Spring的声明式事务

约束声明

xmlns:tx="http://www.springframework.org/schema/tx"

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd

事务配置

<!--https://blog.csdn.net/jiadajing267/article/details/81056057-->
    <!-- 配置声明式事务 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 2. 配置事务属性 -->
    <!--<tx:advice>元素声明事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 根据方法名指定事务的属性 -->
            <tx:method name="*"/>
            <!--propagation配置事务传播行为-->
            <tx:method name="purchase" propagation="REQUIRES_NEW"/>
            <!--isolation配置事务的隔离级别-->
            <tx:method name="update*" isolation="SERIALIZABLE"/>
            <!--rollback-for配置事务遇到异常必须回滚,no-rollback-for配置事务遇到异常必须不能回滚-->
            <tx:method name="add*" rollback-for="java.io.IOException" no-rollback-for="com.dmsd.spring.tx.BookStockException"/>
            <!--read-only配置事务只读属性-->
            <tx:method name="find*" read-only="true"/>
            <!--timeout配置事务的超时属性-->
            <tx:method name="get*" timeout="3"/>
        </tx:attributes>
    </tx:advice>

    <!-- 3. 配置事务切入点, 以及把事务切入点和事务属性关联起来 -->
    <aop:config>
        <aop:pointcut expression="execution(* cn.dai.mapper.UserMapper.*.*(..))"
                      id="txPointCut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>