mybatis从浅入深一步步演变分析

mybatis从浅入深一步步演变分析

版本一:不使用代理(非spring)

package com.yimeng.domain;

public class User {

    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E

### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?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>

    <!--加载属性文件-->
    <properties resource="jdbc.properties"/>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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="userMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>

测试类:

package com.yimeng;

import com.yimeng.domain.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.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {

    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件。
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作
        //指定使用名称空间为userMapper的映射配置文件下id为findAll的sql语句
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //打印数据
        System.out.println("=========================");
        System.out.println(userList);
        System.out.println("=========================");
        //释放资源
        sqlSession.close();
    }
}

pom.xml:

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yimeng</groupId>
    <artifactId>mybatis-nospring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

执行结果:

image-20240924223854217

数据库内容:

image-20240924223922197

数据库内容:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-nospring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-nospring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-nospring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

特点:

image-20240924224511002

image-20240924224731728

这个内容就讲这么多,因为不常用,可以演变为使用代理的版本。

注意:

如果把上面的mapper配置文件的namespace改变了,那么也需要把selectList方法的参数也改变了才行。(因为这种方式必须是要写为namespace.xml的方法名

image-20241031213350983

必须要下面这样才行:

image-20241031214116269

接口取消也是可以的:

image-20241031214209129

版本二:优化版本一。把调用数据层的语句写在对应的地方

我们service层要使用mapper层的方法,去对数据库进行操作,那么我们如果也像上面测试方法中这样写(就把上面的test1方法中的语句当做是service层方法的语句就行了),那么service还要创建SqlSessionFactory、SqlSession等,就不应该写在这里了,service应该不需要知道具体怎么去访问数据库,他就想做到:“给一个mapper层一个参数,然后mapper给他返回对应的数据就行了,service不想要知道具体怎么去执行的。,数据层具体怎么去拿,他不想知道”。所以,我们应该把这些创建SqlSessionFactory、SqlSession等对象的语句放在mapper层。

所以优化如下:

package com.yimeng.domain;

public class User {

    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/9/24 22:53
 * @PackageName:com.yimeng.mapper
 * @ClassName: UserMapper
 * @Description: TODO
 * @Version 1.0
 */
public interface UserMapper {
    public List<User> findAll() throws IOException;
}
package com.yimeng.mapper.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/9/24 22:54
 * @PackageName:com.yimeng.mapper.impl
 * @ClassName: UserMapperImpl
 * @Description: TODO
 * @Version 1.0
 */
public class UserMapperImpl implements UserMapper {
    public List<User> findAll() throws IOException {
        //获得核心配置文件。
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作
        //指定使用名称空间为userMapper的映射配置文件下id为findAll的sql语句
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //释放资源
        sqlSession.close();
        return userList;
    }
}

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-nospring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-nospring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-nospring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

pom.xml

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yimeng</groupId>
    <artifactId>mybatis-nospring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

配置文件:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E

### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?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>

    <!--加载属性文件-->
    <properties resource="jdbc.properties"/>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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="userMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>

测试代码(这里test1中的代码,你可以理解为就是service层中的代码):

package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.mapper.impl.UserMapperImpl;
import org.junit.Test;
import java.io.IOException;
import java.util.List;

public class MyBatisTest {

    @Test
    //查询操作
    public void test1() throws IOException {
        UserMapper userMapper = new UserMapperImpl();
        List<User> userList = userMapper.findAll();
        //打印数据
        System.out.println("=========================");
        System.out.println(userList);
        System.out.println("=========================");
    }
}

结果:

image-20240924230704054

这样的做法,你就可以看到service层(上面的test1)中没有写怎么访问数据库的代码了,这样就符合我们的开发思维了。

版本三:使用代理(非spring)

mybatis动态代理的方式

上面这个版本中,还存在问题,每一个mapper类的方法中都需要写获取session对象的语句,并且mapper层实现类的方法中也要自己调用原生api,自己绑定xml中的sql,就很麻烦,并且很多东西都是按照固定死的一种规则去写的。比如,创建那些核心对象,这个步骤是死的。比如,根据接受值和放回值是什么,确定调用mybatis的哪个原生API,确定去执行哪个xml中的sql,这些语句虽然不是写死的,但是规则基本是固定的。既然这样,那么mybatis就想能不能自动给我们生成对应的代码,我们只要以某种约定告诉他对应的信息就行了。

image-20240924235303338

mybatis确实实现了这个功能。只要我们根据mybatis的约定,提供给mybatis需要的信息,那么他就能自动给我们调用对应原生方法,去执行对应的sql,并封装到对应的类型中去返回给我们。

他是怎么做到的呢?其实就是通过JDK动态代理来实现的。

我们需要提供给他接口(不用提供实现类,mybatis底层自动用JDK动态代理给我们生成对应的实现类和实现类中的方法逻辑),接口的全限定名要对应的xml文件的namespace,并且接口中方法的方法名要和xml中要执行的sql的id一样。这样,mybatis才能自动根据他的约定去判断出要给我们生成的实现类是什么样的,对应的方法的功能是什么样的,我们调用接口中的方法应该去执行哪个sql。其实他就是通过接口提供mybatis需要的信息的,再自动给我们生成对应的实现类的,当然哈,接口必须要告诉给mybatis(必须扫描接口)。接口是通过mybatis的配置文件来告诉mybatis的(通过注解也行,注解和配置文件来告诉mybatis要动态代理哪些接口,这两种方式其实都是一样的,只是方法论不同而已,思想都是一样的,注解底层也是代码,只是封装了一下而已):

扫描的语句:

好,现在我们演示一下mybatis的动态代理。

这里我们先把上面这个代码改造掉去,简单地使用代理,看看怎么使用的。

package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/9/24 22:53
 * @PackageName:com.yimeng.mapper
 * @ClassName: UserMapper
 * @Description: TODO
 * @Version 1.0
 */
public interface UserMapper {
    public List<User> findAll() throws IOException;
}
package com.yimeng.domain;

public class User {

    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E

### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n

### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?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>

    <!--加载属性文件-->
    <properties resource="jdbc.properties"/>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
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.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {

    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件。
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.findAll();
        //打印数据
        System.out.println("=========================");
        System.out.println(userList);
        System.out.println("=========================");
    }
}
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yimeng</groupId>
    <artifactId>mybatis-nospring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

数据库:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-nospring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-nospring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-nospring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

结果:

image-20240925232119300

解释:

这里我们把上面版本二中的代码修改了,看到我们没有写mybatis实现类。

image-20240925232453152

虽然我们没有写实现类,但是我们通过sqlSession.getMapper(对应接口.class)好像还是获取到了UserMapper接口的实现类实例了,其实这个实现类实例就是mybatis给我们动态创建的动态代理对象。

image-20240925232649800

相比于上个版本的代码,我们这里又在service(这里的test1)中写了获取mybatis核心对象的语句了,但是没有关系,这个等到结合spring我们就可以把这些语句交给spring来做了,那样service就又不需要写这些步骤了。

image-20240925233059451

其实包括下面的sqlSession.getMapper(接口.class)这一步,我们都可以交给spring,我们只要在service层注入UserMapper就行了,注入进来的其实就是这里sqlSession.getMapper(接口.class)获取到的代理对象,service层只要直接用这个代理对象就行了,不需要知道怎么创建的。

image-20240925233218168

image-20240925233544652

image-20240925233717922

其实mybatis动态代理的核心就是这个getMapper(接口.class)方法了,如果感兴趣可以自己去阅读源码,这里不展开说具体是怎么做到创建这个代理对象的。

image-20240925233315091

其实mybatis就是在上面的sqlSession.getMapper()方法中进行了动态代理的。

如果想要了解更细,那么可以看sqlSession.getMapper()方法的源码。

mybatis中的动态代理

mybatis虽然使用了动态代理,但是并不是动态代理的常规用法。动态代理可以分为两种,一种是有实现类的,一种是没有实现类的(mybatis使用的就是没有实现类的这种方式),有实现类的那种动态代理,一般的使用是既执行实现类的方法,又执行一些增强的逻辑。没有实现类的效果是,只有增强,没有执行原有实现类的方法(因为都没有实现类)。

大概的效果类似下面这样的代码:

image-20240926223705094

image-20240926000207592

mybatis中动态代理的增强效果是:“通过一系列的信息,然后自动判断出要执行mybatis原生的哪一个API,并把对应的结果返回!”。

这里怎么判断方法是查询一个、查询多个、插入、修改、删除的呢?是通过标签(select、update、delete、insert)或者sql吗?我觉得不是,我觉得他可能有一个内部自己的判断逻辑。因为我试了,在xml中的delete、update的标签内写insert into语句,发现也成功插入的,在insert、update标签内写delete语句,也能删除成功。但是在select标签内写insert into却没有插入成功。

具体的原因我不知道,我不知道这里它是怎么判断执行那个方法的,但是不重要了。反正,我们按照它的规范来写就行了,只要是插入的sql,就写insert标签,只要是update标签,那么就写更新的sql,这样,结果就肯定是我们所想当然的结果了。

值得注意的是:INSERT…ON DUPLICATE KEY UPDATE这种可能是更新,也可能是插入的sql怎么写呢?

这个随便你写insert标签或者update标签都行。

有人可能会问为什么?上面不是说了了嘛!(上面说了"我试了,在xml中的delete、update的标签内写insert into语句,发现也成功插入的,在insert、update标签内写delete语句,也能删除成功……")

INSERT…ON DUPLICATE KEY UPDATE这种其实谁都不好确定是更新或者是插入,所以,也难以通过mybatis的使用规则来确定使用insert还是update标签,但是不重要,使用insert或者update标签,执行都是正确的。就和上面我们说的,在delete、update的标签内写insert into语句也能成功一样,所以我猜想mybatis的select、update、delete、insert标签可能规则是这样的:如果是能影响数据行数的,你使用insert、delete、update标签都行,就是不能使用select标签。

注意:mybatis使用的是jdk动态代理。是基于接口的动态代理。

不写实现类的动态代理怎么写?请看同文件夹下《代理模式》的笔记!

版本四:结合spring的版本

Spring 整合 Mybatis 方式一(非注解、SqlSessionTemplate)

使用配置文件

在mybatis与spring整合后, 通常我们不会直接使用SqlSessionFactory,因为这种方式用起来比较麻烦。

mybatis-spring提供了易于使用的类,如SqlSessionTemplate、SqlSessionDaoSupport等。

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.mapper.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;

public class UserMapperImpl implements UserMapper {

    // 如果通过 @Autowired进行注入,那么set方法不需要写。但是这里使用xml注入,所以需要提供这个set方法(当然你使用构造注入也行)。
//    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> findAll(){
        // 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
//    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!--    <environments default="developement">-->
<!--        <environment id="developement">-->
<!--            <transactionManager type="JDBC"/>-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!--                <property name="username" value="root"/>-->
<!--                <property name="password" value="815924"/>-->
<!--            </dataSource>-->
<!--        </environment>-->
<!--    </environments>-->

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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">

    <!--注册mapper的bean-->
    <bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
        <!--注入bean-->
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-integrate-sping</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

数据库数据:

image-20241019214617259

执行结果:

image-20241019003717878

细心的读者注意到,在mybatis-config.xml文件中并没有配置、、等元素。因为mybatis-config.xml文件中即使配置了这些标签,也会被SqlSessionFactoryBean忽略。这里的这种方式使用mybatis我们需要显式的为SqlSessionFactoryBean的dataSource属性注入对应Bean才行,如果不是这样做的话,项目在其初始化时就会抛出异常。

比如:

image-20241022120354655

注意:上面这个spring集成mybatis写的mybatis-config.xml是放到SqlSessionFactoryBean中的一些配置信息。而之前我们写的mybatis在非spring下的时候中,写的那个sqlMapConfig.xml和这里这个配置是不一样的。

虽然写的内容你看起来是类似的,但是其实不是一个东西。之前sqlMapConfig.xml配置文件的时候是SqlSessionFactoryBuilder创建SqlSessionFactory对象需要的,这里我们写的配置文件是SqlSessionFactoryBean对象需要的。他们两个不是一个东西,所以能写的东西也不是完全一样的(虽然有部分内容是完全一样的写法的)。

使用不同的东西,用法也不同,这个是可以理解的,你也知道,我们去写一个代码去完成一样的东西,但是实现方式肯定也不止一种。不同实现方式使用起来的规则肯定也是不一样的,所以没有必要纠结为什么这里两种配置方式为什么不一样,没必要纠结实现这个某个的方法论为什么不同,去实现一个目标走不同的路是很正常的。

mybatis集成spring和不集成spring的一部分区别
区别1

没有使用spring的时候,是用的DefaultSqlSession获取代理对象的。

image-20241019010707976

使用spring的时候,是用的SqlSessionTemplate获取代理对象的。

image-20241019010429949

image-20241019010826067

所以还是有一些不同的。

不管是DefaultSqlSession还是SqlSessionTemplate都是其实都是我们说的Sqlsession,你看他们都是实现了SqlSession接口。

image-20241019215235691

image-20241019210755364

但是注意哈,SqlSessionTemplate底层其实还是用的DefaultSqlSession。SqlSessionTemplate对DefaultSqlSession进行了封装,解决了一些问题。

关于SqlSessionTemplate和DefaultSqlSession的区别,具体的可以看本文件夹的另一篇笔记《spring集成mybatis为什么不用写核心类》。

区别2

还要注意一点:spring整合 mybatis之后,事务默认是自动提交的,不需要手动提交。

对比:

上面我们展示的“版本三:使用代理(非spring)”的案例中(为什么不说“版本一:不使用代理(非spring)”,因为这个版本不常用),没有使用增删改,只有查询,那个时候没有用事务,是因为查询是不需要事务的,所以这里我们重新写一个案例对比一下。这里我们也重新写一个“Spring 整合 Mybatis 方式一(非注解、SqlSessionTemplate)”,作为对比。

数据库:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring-contrast
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring-contrast` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring-contrast`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

image-20241020004958515

不使用spring,并且没有进行提交事务的插入(删除、修改也是类似的,这里就演示新增):

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();

    public int insertUser(User user);
}
package com.yimeng.service.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserServiceImpl implements UserService {

    @Override
    public List<User> findAll() throws IOException {
        //获得核心配置文件。
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.findAll();
        sqlSession.close();

        return userList;
    }

    @Override
    public int insertUser(User user) throws IOException {
        //获得核心配置文件。
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        int row = userMapper.insertUser(user);
        // 要提交才行。不然插入无效。
//        sqlSession.commit();
        sqlSession.close();
        return row;
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;

public interface UserService {
    public List<User> findAll() throws IOException;

    public int insertUser(User user) throws IOException ;
}
package com;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import com.yimeng.service.impl.UserServiceImpl;

import java.io.IOException;

/**
 * @Author yimeng
 * @Date 2024/10/20 0:51
 * @PackageName:com
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) throws IOException {

        UserService userService = new UserServiceImpl();
        System.out.println("插入前查询:"+userService.findAll());

        User user = new User();
        user.setUsername("test");
        user.setPassword("123456");
        userService.insertUser(user);

        System.out.println("插入后查询:"+userService.findAll());
    }
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-spring-contrast
jdbc.username=root
jdbc.password=815924
<?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>

    <!--加载属性文件-->
    <properties resource="jdbc.properties"/>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

    <insert id="insertUser">
        INSERT INTO user(username,password) VALUES (#{username},#{password})
    </insert>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-nospring-contrast</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
    </dependencies>

</project>

执行结果:

image-20241020005352293

image-20241020005422251

加上提交事务后,执行的结果(和上面代码的不同就只是这里执行打开了sqlSession.commit();注释而已,所以就不贴代码了):

image-20241020005651465

image-20241020010521071

看到提交事务就成功插入了,看来没有集成spring的mybatis中是手动提交事务才行的(当然哈,你使用openSession(ture)也行,开启自动提交事务,如果没有开启自动提交事务,那么就必须手动提交事务了)。

在spring版本下的mybatis:

数据库还是继续用上面的数据哈。

image-20241020010521071

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}
package com.yimeng.mapper.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;

public class UserMapperImpl implements UserMapper {

    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> findAll(){
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.findAll();
    }

    @Override
    public int insertUser(User user){
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.insertUser(user);
    }
}
package com.yimeng.mapper;

import com.yimeng.domain.User;

import java.util.List;

public interface UserMapper {
    public List<User> findAll();

    public int insertUser(User user);
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;

import java.util.List;

public class UserServiceImpl implements UserService {
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    public int insertUser(User user){
        return userMapper.insertUser(user);
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;

import java.util.List;

public interface UserService {
    public List<User> findAll();

    public int insertUser(User user);
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        System.out.println("插入前查询:"+userService.findAll());

        User user = new User();
        user.setUsername("spring");
        user.setPassword("123456");
        userService.insertUser(user);

        System.out.println("插入后查询:"+userService.findAll());
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
    <!--    <environments default="developement">-->
    <!--        <environment id="developement">-->
    <!--            <transactionManager type="JDBC"/>-->
    <!--            <dataSource type="POOLED">-->
    <!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--                <property name="username" value="root"/>-->
    <!--                <property name="password" value="815924"/>-->
    <!--            </dataSource>-->
    <!--        </environment>-->
    <!--    </environments>-->

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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">

    <!--注册mapper的bean-->
    <bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
        <!--注入bean-->
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring-contrast"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

    <insert id="insertUser">
        INSERT INTO user(username,password) VALUES (#{username},#{password})
    </insert>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-spring-contrast</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

执行结果:

image-20241020010908727

image-20241020010922636

所以,看到在spring整合mybatis中使用mybatis,没有手动提交事务,也没有去手动开启自动提交,结果也是可以成功进行插入的。(PS:可能在SqlSessionTemplate内部已经进行开启了自动提交了!所以这里不用显示开启自动提交也可以做到执行完毕就影响数据库。)

不使用配置文件(不抽取mybatis-config.xml)

例子:

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;

public class UserMapperImpl implements UserMapper {

    // 如果通过 @Autowired进行注入,那么set方法不需要写
//    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> findAll(){
        // 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        return userMapper.findAll();
    }
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">

    <!--注册mapper的bean-->
    <bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
        <!--注入bean-->
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
<!--        &lt;!&ndash;通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。&ndash;&gt;-->
<!--        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>-->

        <property name="typeAliasesPackage" value="com.yimeng.domain"/>
        <!--从类路径下加载在mybatis/mappers包和它的子包中所有的 MyBatis 映射器 XML 文件-->
        <property name="mapperLocations" value="classpath*:mybatis/mappers/**/*.xml"></property>
        <property name="configuration">
            <bean class="org.apache.ibatis.session.Configuration">
                <!--忽略大小写-->
                <property name="mapUnderscoreToCamelCase" value="true"/>
                <!--开启缓存-->
                <property name="cacheEnabled" value="true"/>
                <!--使用默认的执行器-->
                <property name="defaultExecutorType" value="SIMPLE"/>
            </bean>
        </property>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-integrate-spring-noconfig</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

数据库:

image-20241022222056812

执行结果:

image-20241022221922878

解释:从mybatis-spring 1.3.0之后,我们可以移除mybatis-config.xml文件,将所有关于myabtis的配置都通过SqlSessionFactoryBean来指定。即,可以不用通过<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>,引入mybatis一些其他的配置信息。

总之,之前的做法中(mybatis-spring 1.3.0之前),有一部分配置只能在SqlSessionFactoryBean通过注入配置(比如数据源),还有一部分配置,只能通过xml配置文件配置,然后再通过<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>把那部分的配置文件给到SqlSessionFactoryBean。

但是在mybatis-spring 1.3.0之后,我们之前只能通过写到xml配置文件中,然后再通过<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>把那部分的配置文件给到SqlSessionFactoryBean的那些信息也可以直接写到SqlSessionFactoryBean中了。

mybatis-spring 1.3.0之前的做法:

image-20241022222620059

mybatis-spring 1.3.0之后可以的做法(当然哈,mybatis-spring 1.3.0之后也可以用mybatis-spring 1.3.0之前的写法,即,mybatis-spring 1.3.0之后也可以像mybatis-spring 1.3.0之前一样,把那些特别的配置抽取为一个配置文件,然后再在SqlSessionFactoryBean中引入这个配置文件):

image-20241022222419804

当然,使用mybatis配置文件和不使用mybatis配置文件的做法都是可以的,看你喜欢。

Spring 整合 Mybatis 方式二(非注解、SqlSessionDaoSupport)

只要改一部分东西就行了。

image-20241019214217084

image-20241019214326626

完整代码:

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

//    // 如果通过 @Autowired进行注入,那么set方法不需要写
    @Autowired
//    private SqlSessionTemplate sqlSessionTemplate;
//
//    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
//        this.sqlSessionTemplate = sqlSessionTemplate;
//    }

    @Override
    public List<User> findAll(){
        // 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
//        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        UserMapper userMapper = getSqlSession().getMapper(UserMapper.class);
        return userMapper.findAll();
    }
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
    <!--    <environments default="developement">-->
    <!--        <environment id="developement">-->
    <!--            <transactionManager type="JDBC"/>-->
    <!--            <dataSource type="POOLED">-->
    <!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--                <property name="username" value="root"/>-->
    <!--                <property name="password" value="815924"/>-->
    <!--            </dataSource>-->
    <!--        </environment>-->
    <!--    </environments>-->

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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">

    <!--注册mapper的bean-->
    <bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
        <!--注入bean-->
<!--        <property name="sqlSessionTemplate" ref="sqlSession"/>-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

<!--    使用SqlSessionDaoSupport就可以不用写这个SqlSessionTemplate了。之前写这个SqlSessionTemplate是因为mapper实现类中需要注入这个。上面UserMapperImpl中注入了sqlSessionFactory就行了。内部可能自己创建了SqlSessionTemplate。-->
<!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!--        <constructor-arg ref="sqlSessionFactory"/>-->
<!--    </bean>-->
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-integrate-spring2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

数据库数据:

image-20241019214651315

执行结果:

image-20241019214713505

sqlSessionDapSupport其实就是对sqlSessionTemplate 又封装了一次而已。

image-20241020011803175

为什么注入sqlSessionFactory?

image-20241020012551993

补充:其实继承SqlSessionDaoSupport的类你给他一个sqlSessionFactory 或 sqlSessionTemplate 属性都行的,虽然上面我只展示了sqlSessionFactory 属性哈。如果两者都被设置了 , 那么SqlSessionFactory是被忽略的。

原因:

image-20241020014553326

我们看到setSqlSessionFactory(SqlSessionFactory sqlSessionFactory)方法中需要的是SqlSessionFactory 类型,但是我们却给他一个SqlSessionFactoryBean类型的bean。

SqlSessionFactoryBean和SqlSessionFactory 没有继承或者实现的关系。但是为什么可以呢?

这个是因为SqlSessionFactoryBean继承了FactoryBean,继承这个接口就说明是一个工厂类,spring注册这个bean的时候会调用它的getObject,把getObject的返回对象放到spring容器中,作为bean指向的对象,这个getObject方法返回的对象就是SqlSessionFactory类型的,所以setSqlSessionFactory(SqlSessionFactory sqlSessionFactory)方法中需要的是SqlSessionFactory 类型,但是我们给他一个SqlSessionFactoryBean类型的bean,就可以成功。

注意:一般的类,我们set方法的形参类型是什么,我们需要注入的类型就是什么(子类或者实现类应该也能注入),但是工厂Bean不同,他注入的是该工厂Bean的getObject方法所返回的对象。

image-20241020015227744

image-20241020015249690

Spring整合Mybatis方式三(非注解、MapperFactoryBean)

无论是使用SqlSessionTemplate,还是继承SqlSessionDaoSupport,我们都需要手工编写DAO类的代码,手动使用getMapper()方法获取代理对象,然后调用对应的方法。

但是在与spring进行整合时,是否有更加简单的使用方法呢?能否通过@Autowired注解或者spring配置文件直接注入Mapper呢?

我们期望的使用方式是这样:

public class UserService {
    @Autowired
    private UserMapper userMapper;
    public void insert(User user){
        userMapper.insert(user);
    }
}

或者在spring的xml中配置,再直接:

public class UserService {
    private UserMapper userMapper;
    
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    public void insert(User user){
        userMapper.insert(user);
    }
}

在没有进行任何配置的情况下,直接这样操作显然是会报错的,因为UserMapper是一个接口,且不是spring管理的bean,因此无法直接注入

所以应该怎么做呢?直接看下面操作就行了。这里只展示使用xml的方式配置bean。

例子:

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
    <!--    <environments default="developement">-->
    <!--        <environment id="developement">-->
    <!--            <transactionManager type="JDBC"/>-->
    <!--            <dataSource type="POOLED">-->
    <!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--                <property name="username" value="root"/>-->
    <!--                <property name="password" value="815924"/>-->
    <!--            </dataSource>-->
    <!--        </environment>-->
    <!--    </environments>-->

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

<!--    这里没有mapper实现类,所以也没有注入SqlSessionTemplate属性。自动生成实现类,他内部就自动用了SqlSessionTemplate,所以不需要我们手动来注册这个bean了。-->
<!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!--        <constructor-arg ref="sqlSessionFactory"/>-->
<!--    </bean>-->
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-mapperFactoryBean</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

数据库:

image-20241022224637507

执行结果:

image-20241022224652826

这里我们看到,使用了

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />
	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

后,我们都不用写实现类了。

事实上,其底层是通过对UserMapper接口进行JDK动态代理,内部自动生成代理类,并且智能按照mybatis内部的约定去对应的地方取信息,再使用SqlSessionTemplate完成我们想要的操作(当然,我们的想要能让他自动生成实现了,那么我们的使用就要符合mybatis的约定哈,比如,xml的namespace要写成他对应接口的接口全限定类名)。

使用MapperMapperFactoryBean和SqlSessionDaoSupport的区别:

主要在于是否有自己写mapper实现类、注入userMapper的方式。

MapperMapperFactoryBean:

image-20241022230414448

SqlSessionDaoSupport:

image-20241022230530473

Spring整合Mybatis方式四(非注解MapperScannerConfigurer)

通过MapperFactoryBean配置,已经是mybatis与spring进行时理想的方式了,我们可以简单的通过@Autowired注解或者spring的配置文件进行注入。

但是如果有许多的Mapper接口要配置,针对每个接口都配置一个MapperFactoryBean,会使得我们的配置文件很臃肿。关于这一点,mybatis-spring包中提供了MapperScannerConfigurer来帮助你解决这个问题。

MapperScannerConfigurer可以指定扫描某个包,然后为这个包下的所有Mapper接口都自动生成实现类,效果和把这个扫描的包下所有的接口都用MapperFactoryBean注册为spring的bean一样。

例子:

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

/**
 * @Author yimeng
 * @Date 2024/10/18 16:38
 * @PackageName:com.yimeng
 * @ClassName: Main
 * @Description: TODO
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
    <!--    <environments default="developement">-->
    <!--        <environment id="developement">-->
    <!--            <transactionManager type="JDBC"/>-->
    <!--            <dataSource type="POOLED">-->
    <!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--                <property name="username" value="root"/>-->
    <!--                <property name="password" value="815924"/>-->
    <!--            </dataSource>-->
    <!--        </environment>-->
    <!--    </environments>-->

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

<!--    这里没有mapper实现类,所以也没有注入SqlSessionTemplate属性。自动生成实现类,他内部就自动用了SqlSessionTemplate,所以不需要我们手动来注册这个bean了。-->
<!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!--        <constructor-arg ref="sqlSessionFactory"/>-->
<!--    </bean>-->
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-mapperScannerConfigurer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

image-20241022234937118

执行结果:

image-20241022232957147

和上面使用MapperScannerConfigurer的区别就是:

<!--    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->

替换为了:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.yimeng.mapper" />
	<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

image-20241022233038572

注意:basePackage 属性是用于指定Mapper接口的包路径。如果的Mapper接口位于不同的包下,可以使用分号”;”或者逗号”,”进行分割。

比如:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="aa.bb.mapper;aa.dd.mapper" />
</bean>

如果某个路径还包含子包,子包中的Mapper接口递归地被搜索到。因此对于上述配置,我们可以通过公共的包名进行简化。如:

 <property name="basePackage" value="aa" />

你可能想到了,如果指定的公共的包名下面还包含了一些其他的接口,这些接口是你作为其他用途使用到的,并不能作为mybatis的Mapper接口来使用。此时,你可以通过markerInterface属性或者annotationClass属性来进行过滤。

markerInterface属性,顾名思义,通过定义一个标记接口(接口中不需要定义任何方法),来对Mapper映射器接口进行过滤,如:

public interface MapperInterface{}

接着,你需要将你的映射器接口继承MapperInterface,如:

public interface UserMapper extends MapperInterface{
   public void insert(User user);
}

此时你可以为MapperScannerConfigurer指定只有继承了MapperInterface接口的子接口,才为其自动注册MapperFactoryBean,如:

<property name="markerInterface" value=“com.tianshouzhi.mybatis.MybatisMapperInterface"/>

annotationClass属性的作用是类似的,只不过其是根据注解进行过滤。你不需要自定义注解,mybatis已经提供了一个@Mapper注解,你直接使用即可。配置如下:

<property name="annotationClass" value="org.apache.ibatis.annotations.Mapper"/>

下面演示一下多个mapper的例子

package com.yimeng.config;

// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
    
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class Dept {
    private int id;
    private String name;
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class Role {
    private int id;
    private String name;
    private String description;
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.Dept;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface DeptMapper extends YMMapperInterface {
    List<Dept> getAllDepartments();
}
package com.yimeng.mapper;

import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserMapper extends YMMapperInterface {
    public List<User> findAll();
}
package com.yimeng.mapper2;

import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.Role;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface RoleMapper extends YMMapperInterface {
    List<Role> getAllRoles();
}
package com.yimeng.service.impl;

import com.yimeng.domain.Dept;
import com.yimeng.mapper.DeptMapper;
import com.yimeng.service.DeptService;
import java.util.List;

public class DeptServiceImpl implements DeptService{

    private DeptMapper deptMapper;
    @Override
    public List<Dept> getAllDepartments(){
        return deptMapper.getAllDepartments();
    }

    public void setDeptMapper(DeptMapper deptMapper) {
        this.deptMapper = deptMapper;
    }
}
package com.yimeng.service.impl;


import com.yimeng.domain.Role;
import com.yimeng.mapper2.RoleMapper;
import com.yimeng.service.RoleService;
import java.util.List;

public class RoleServiceImpl implements RoleService {
    private RoleMapper roleMapper;

    public void setRoleMapper(RoleMapper roleMapper) {
        this.roleMapper = roleMapper;
    }

    @Override
    public List<Role> getAllRoles(){
        return roleMapper.getAllRoles();
    }
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {

    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.Dept;
import java.util.List;

public interface DeptService {
    List<Dept> getAllDepartments();
}
package com.yimeng.service;

import com.yimeng.domain.Role;
import com.yimeng.domain.User;
import java.util.List;

public interface RoleService {
    List<Role> getAllRoles();
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.Dept;
import com.yimeng.domain.Role;
import com.yimeng.domain.User;
import com.yimeng.mapper.DeptMapper;
import com.yimeng.service.DeptService;
import com.yimeng.service.RoleService;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);

        // 获取bean并执行
        DeptService deptService = (DeptService) ctx.getBean("deptService");
        List<Dept> allDepartments = deptService.getAllDepartments();
        System.out.println(allDepartments);

        // 获取bean并执行
        RoleService roleService = (RoleService) ctx.getBean("roleService");
        List<Role> allRoles = roleService.getAllRoles();
        System.out.println(allRoles);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
        <typeAlias type="com.yimeng.domain.Dept" alias="dept"/>
        <typeAlias type="com.yimeng.domain.Role" alias="role"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
        <mapper resource="DeptMapper.xml"/>
        <mapper resource="RoleMapper.xml"/>
    </mappers>
</configuration>

注意:下面这里的xml中写了四种mapper接口的扫描方式,你想要试一下哪一种就打开对应的注释就行了。

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

    <!--下面四种自动生成实现类的做法都是可以的,随便打开一种方式的注释,执行都是成功的。你选一个自己喜欢的就行了。其中方式一的做法最麻烦,需要给每一个要让mybatis自动生成实现类的接口都注册一遍。其他三种方式都是蛮方便的。其中第四中方式中,需要在mapper接口上面加上@Mapper注解,作为标记,这样mybatis知道要把basePackage下的这些接口进行自动生成实现类。其中第三种做法,我们就需要自己定义一个接口,接口随便叫都行,然后让需要自动生成实现类的mapper接口们都继承这个接口,最后告诉mybatis,标记的接口叫什么名字。其实,只要符合规范,第二种做法就是最简单的,我们只要约定,把mapper接口都放在指定包下就行了,这样我们都不用标记。-->

    <!--自动生成实现类方式四。-->
    <!--使用@Mapper注解来标记要让mybatis自动生成实现类的接口也行。需要做到在每一个mapper接口上面加上@Mapper注解。不要忘了,这个basePackage写的包名是这几个mapper公共包哈。在公共包下,不需要让mybatis生成实现类的那些接口就不用加上@Mapper注解了。使用接口标记的方式不需要加@Mapper注解哈。接口标记和@Mapper注解标记要让mybatis生成的实现类都行,你二选一就行了。接口标记法,接口是要你自己定义的。但是@Mapper是不需要你自己定义注解的,这个@Mapper是mybatis自带的。-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!--使用Mapper注解来标记要让mybatis自动生成实现类的接口也行。-->
        <property name="annotationClass" value="org.apache.ibatis.annotations.Mapper"/>
    </bean>

    <!--自动生成实现类方式三。-->
    <!--扫描是包括扫描子包的,所以,下面的做法,我们可以用这个方式来做。-->
    <!--如果指定的公共的包名下面还包含了一些其他的接口,这些接口是你作为其他用途使用到的,并不能作为mybatis的Mapper接口来使用,那么我们可以通过通过markerInterface属性或者annotationClass属性来进行过滤。当然,不过滤也行,倒是不会直接报错,只是会给你警告,不影响运行。-->
<!--    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">-->
<!--        <property name="basePackage" value="com.yimeng" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!--        &lt;!&ndash;告诉mybatis,只有继承YMMapperInterface接口的接口,才让mybatis自动生成实现类。&ndash;&gt;-->
<!--        <property name="markerInterface" value="com.yimeng.config.YMMapperInterface"/>-->
<!--    </bean>-->

    <!--自动生成实现类方式二。-->
    <!--扫描包的话,就可以替代给每一个mapper写MapperFactoryBean了。可以代替下面那个注释掉的写法。如果有多个包要扫描,那么使用;或者,分开就行。-->
<!--    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">-->
<!--&lt;!&ndash;        <property name="basePackage" value="com.yimeng.mapper;com.yimeng.mapper2" />&ndash;&gt;-->
<!--        <property name="basePackage" value="com.yimeng.mapper,com.yimeng.mapper2" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!--    </bean>-->

    <!--自动生成实现类方式一。-->
    <!--下面这样写就可以不用写实现类了。-->
    <!--如果不是扫描包的话,要一个个写。-->
<!--    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->
<!--    <bean id="deptMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.yimeng.mapper.DeptMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->
<!--    <bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--        <property name="mapperInterface" value="com.yimeng.mapper2.RoleMapper" />-->
<!--        <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!--    </bean>-->

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>
    <!--注册Service的bean-->
    <bean id="deptService" class="com.yimeng.service.impl.DeptServiceImpl">
        <!--注入bean-->
        <property name="deptMapper" ref="deptMapper"/>
    </bean>
    <!--注册Service的bean-->
    <bean id="roleService" class="com.yimeng.service.impl.RoleServiceImpl">
        <!--注入bean-->
        <property name="roleMapper" ref="roleMapper"/>
    </bean>
    <!--注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
        <!--其他配置-->
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

<!--    这里没有mapper实现类,所以也没有注入SqlSessionTemplate属性。自动生成实现类,他内部就自动用了SqlSessionTemplate,所以不需要我们手动来注册这个bean了。-->
<!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!--        <constructor-arg ref="sqlSessionFactory"/>-->
<!--    </bean>-->
</beans>
<?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.yimeng.mapper.DeptMapper">

    <!--查询操作-->
    <select id="getAllDepartments" resultType="dept">
        SELECT * FROM dept
    </select>
</mapper>
<?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.yimeng.mapper2.RoleMapper">

    <!--查询操作-->
    <select id="getAllRoles" resultType="role">
        SELECT * FROM roles
        </select>
</mapper>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-multi-mapper</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

数据库数据:

image-20241024224736150

image-20241024224748416

image-20241024224758628

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `dept` */

DROP TABLE IF EXISTS `dept`;

CREATE TABLE `dept` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `dept` */

insert  into `dept`(`id`,`name`) values (1,'人事部'),(2,'开发组'),(3,'商品部');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `roles` */

DROP TABLE IF EXISTS `roles`;

CREATE TABLE `roles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `NAME` varchar(255) NOT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `roles` */

insert  into `roles`(`id`,`NAME`,`description`) values (1,'普通员工','基本权限'),(2,'管理员','更高级的权限');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241024224710902

Spring整合Mybatis方式五(注解的方式@MapperScan)

如果读者习惯使用注解,而不是xml文件的方式进行配置,mybatis-spring提供了@MapperScan注解,其可以取代MapperScannerConfigurer。

一些读者可能在springboot中也使用过@MapperScan注解,那个是springboot启动类提供的注解。这里我们要用的**@MapperScan注解是mybatis-spring中提供的,并不是mybatis-springboot-starter中提供的**。这一点值得注意,不要导错包了。

以下演示了如何通过@MapperScan注解的方式来配置mybatis与spring整合,注解中的属性可以与MapperScannerConfigurer相对应。

package com.yimeng.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import javax.sql.DataSource;

@Configuration
@MapperScan(
        //等价于MapperScannerConfigurer的basePackage属性。扫描mapper接口的包路径,自动生成实现类。加上mapper包扫描,即basePackages属性,并且指定了markerInterface或者annotationClass,那么只有标记的接口自动生成实现类。但是,如果只写basePackages属性,不指定markerInterface或者annotationClass,那么这个包下的接口都会被自动生成实现类。
        basePackages = "com.yimeng.mapper",
//        //等价于MapperScannerConfigurer的markerInterface属性。自定义标记要生成实现类的接口。
//        markerInterface = YMMapperInterface.class,
//        //等价于MapperScannerConfigurer的annotationClass属性。使用mybatis的标记接口。
//        annotationClass = Mapper.class,
        //等价于MapperScannerConfigurer的sqlSessionFactoryBeanName属性
        sqlSessionFactoryRef = "sqlSessionFactory"
)
public class DataBaseConfig {
    //定义数据源
    @Bean
    public DataSource dataSource() {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("815924");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring");
        dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
        return dataSource;
    }
    //定义SqlSessionFactoryBean
    @Autowired
    @Bean("sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setDataSource(dataSource);
        ssfb.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
        return ssfb;
    }
}
package com.yimeng.config;

// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

//@Mapper
//public interface UserMapper extends YMMapperInterface {
public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

// 使用@Autowired注解,可以省略set方法
//    public void setUserMapper(UserMapper userMapper) {
//        this.userMapper = userMapper;
//    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import org.springframework.stereotype.Service;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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.xsd">
    
<!--    &lt;!&ndash;注册Service的bean&ndash;&gt;-->
<!--    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">-->
<!--        &lt;!&ndash;注入bean&ndash;&gt;-->
<!--        <property name="userMapper" ref="userMapper"/>-->
<!--    </bean>-->

    <!-- 扫描包。想要用注解@Service等bean的注解,那么就要使用这个扫描。 -->
    <context:component-scan base-package="com.yimeng"/>
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
    @Resource
    private UserService userService;
    @Test
    public void test(){
        List<User> userServiceAll = userService.findAll();
        System.out.println(userServiceAll);
    }
}
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-spring-annotate</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241027115458570

分析1:

这里的案例中把上面“Spring整合Mybatis方式四(非注解MapperScannerConfigurer)”的basePackage、sqlSessionFactory、annotationClass、markerInterface都替代了。

image-20241027115717052

image-20241027115818158

注意:上面注解中说替代的sqlSessionFactoryBeanName和sqlSessionFactory属性不是一样的。这个等一下讲。这里你就认为注解写法的sqlSessionFactoryRef是替代xml中的sqlSessionFactory的就行了。(其实他们的关系是:在xml中sqlSessionFactoryBeanName是替代sqlSessionFactory的,因为使用sqlSessionFactory可能会出现问题,而注解写法中的sqlSessionFactoryRef属性是替代xml中MapperScannerConfigurer的sqlSessionFactoryBeanName属性的。关于MapperScannerConfigurer的sqlSessionFactoryBeanName属性等一下讲。)

分析2:

注解的写法中替代数据源和sqlSessionFactory这个bean的注入。

image-20241027120321569

image-20241027120437234

分析3:

image-20241027120519001

image-20241027120912221

注意:配置信息抽取的问题(MapperScannerConfigurer注入sqlSessionFactory和sqlSessionTemplate属性会出现的问题)

注意:MapperScannerConfigurer的sqlSessionFactory和sqlSessionTemplate属性已经不建议使用了。原因在于,这两个属性不支持你使用spring提供的PropertyPlaceholderConfigurer的属性替换。

例如:你配置了SqlSessionFactoryBean来创建SqlSessionFactory实例,前面已经看到必须为其指定一个dataSource属性。很多用户习惯将数据源的配置放到一个独立的配置文件,如jdbc.properties文件中,之后在spring配置中,通过占位符来替换,如:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
     <property name="username" value="${jdbc.username}"/>
     <property name="password" value="${jdbc.password}"/>
     <property name="url" value="${jdbc.url}"/>
     <property name="driverClassName" value="${jdbc.driver}"/>
</bean>

对于这样的配置,spring在初始化时会报错,因为MapperScannerConfigurer会在PropertyPlaceholderConfigurer初始化之前,就加载dataSource的配置,而此时PropertyPlaceholderConfigurer还未准备好替换的占位符的内容,所以抛出异常。

演示一下之前的例子(之前使用MapperScannerConfigurer扫描的例子):

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        System.out.println("UserService的findAll方法执行 ...");
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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.xsd">

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!--        <property name="sqlSessionTemplate" ref="sqlSession"/>-->

        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--    注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
    </bean>

    <!--    &lt;!&ndash;加载外部的properties文件&ndash;&gt;-->
    <!--    <context:property-placeholder location="classpath:jdbc.properties"/>-->

    <!--    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--        <property name="username" value="${jdbc.username}"/>-->
    <!--        <property name="password" value="${jdbc.password}"/>-->
    <!--        <property name="url" value="${jdbc.url}"/>-->
    <!--        <property name="driverClassName" value="${jdbc.driver}"/>-->
    <!--    </bean>-->

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
    <!--        <constructor-arg ref="sqlSessionFactory"/>-->
    <!--    </bean>-->
</beans>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-spring
jdbc.username=root
jdbc.password=815924
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-spring-MapperScannerConfigurer-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241027161910172

现在是正常的。

但是如果我们使用抽取的数据源呢?

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

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!--        <property name="sqlSessionTemplate" ref="sqlSession"/>-->

        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--    &lt;!&ndash;    注入数据源。使用druid来配置数据源。&ndash;&gt;-->
    <!--    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--        <property name="username" value="root"/>-->
    <!--        <property name="password" value="815924"/>-->
    <!--    </bean>-->

    <!--加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
    <!--        <constructor-arg ref="sqlSessionFactory"/>-->
    <!--    </bean>-->
</beans>

image-20241027162226326

执行结果:

image-20241027162520518

原因是:MapperScannerConfigurer会在PropertyPlaceholderConfigurer初始化之前,就加载dataSource的配置,而此时PropertyPlaceholderConfigurer还未准备好替换的占位符的内容,所以抛出异常。

解决方案:

我们可以使用另外属性来替代:

  • sqlSessionFactoryBeanName替代sqlSessionFactory属性。
<?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.xsd">

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <!--        <property name="sqlSessionTemplate" ref="sqlSession"/>-->

        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>-->
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--    &lt;!&ndash;    注入数据源。使用druid来配置数据源。&ndash;&gt;-->
    <!--    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--        <property name="username" value="root"/>-->
    <!--        <property name="password" value="815924"/>-->
    <!--    </bean>-->

    <!--加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <!--    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
    <!--        <constructor-arg ref="sqlSessionFactory"/>-->
    <!--    </bean>-->
</beans>

image-20241027165234763

如果你之前不是用sqlSessionFactory的,而是用sqlSessionTemplate的(MapperScannerConfigurer中写sqlSessionFactory和sqlSessionTemplate都是可以的,注入任何一个都行),也是同理,可以使用sqlSessionTemplateBeanName代替sqlSessionTemplate属性。

即,注入sqlSessionFactory和sqlSessionTemplate的效果是一样的。sqlSessionTemplateBeanName是替代sqlSessionTemplate解决占位符问题的。sqlSessionFactoryBeanName是替代sqlSessionFactory属性解决占位符问题的。

下面也展示一下具体的使用:

image-20241027165031897

image-20241027163445760

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

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <property name="sqlSessionTemplate" ref="sqlSession"/>

        <!--        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--    注入数据源。使用druid来配置数据源。-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
        <property name="username" value="root"/>
        <property name="password" value="815924"/>
    </bean>

    <!--    &lt;!&ndash;加载外部的properties文件&ndash;&gt;-->
    <!--    <context:property-placeholder location="classpath:jdbc.properties"/>-->

    <!--    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--        <property name="username" value="${jdbc.username}"/>-->
    <!--        <property name="password" value="${jdbc.password}"/>-->
    <!--        <property name="url" value="${jdbc.url}"/>-->
    <!--        <property name="driverClassName" value="${jdbc.driver}"/>-->
    <!--    </bean>-->

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>

执行结果:

image-20241027163528300

看到是可以的。

如果我们使用抽取的数据源会怎么样呢?

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

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <property name="sqlSessionTemplate" ref="sqlSession"/>

        <!--        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--        &lt;!&ndash;    注入数据源。使用druid来配置数据源。&ndash;&gt;-->
    <!--        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--            <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--            <property name="username" value="root"/>-->
    <!--            <property name="password" value="815924"/>-->
    <!--        </bean>-->

    <!--加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>

image-20241027164714104

执行结果:

image-20241027163828794

解决方案:

我们可以使用另外属性来替代:

  • sqlSessionTemplateBeanName替代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"
       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">

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <!--        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <!--        <property name="sqlSessionTemplate" ref="sqlSession"/>-->

        <!--        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <property name="sqlSessionTemplateBeanName" value="sqlSession"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--        &lt;!&ndash;    注入数据源。使用druid来配置数据源。&ndash;&gt;-->
    <!--        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
    <!--            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
    <!--            <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
    <!--            <property name="username" value="root"/>-->
    <!--            <property name="password" value="815924"/>-->
    <!--        </bean>-->

    <!--加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>
</beans>

image-20241027164226926

执行结果:

image-20241027164258291

总之:

写死数据源,你MapperScannerConfigurer中注入sqlSessionFactory属性或者sqlSessionTemplate都行,这两个是选择一个注入就可以了,效果一样。但是,如果是要抽取的数据源,你得使用sqlSessionFactoryBeanName替代sqlSessionFactory,或者使用sqlSessionTemplateBeanName替代sqlSessionTemplate才行。

事务(xml和注解两者都试试)

配置文件版本

事务在spring整合mybatis中也很常用。所以这里也展示一些事务的整合配置。

xml的做法:

配置上下面配置信息。

<!--spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--默认事务超时时间-->
    <property name="defaultTimeout" value="30000"/>
    <!--数据源-->
    <property name="dataSource" ref="dataSource" />
    <!--提交失败的话,也进行回滚-->
    <property name="rollbackOnCommitFailure" value="true"/>
</bean>
<!--开启声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>

然后在对应方法上面添加注解就行了:

@Transactional(rollbackFor = Exception.class)

具体例子:

package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();

    public int updateUserName(User user);
}
package com.yimeng.service.impl;


import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

public class UserServiceImpl implements UserService {
    //    @Autowired
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUserName(Integer id,String name1, String name2)  {
        User user1= new User();
        user1.setId(id);
        user1.setUsername(name1);
        userMapper.updateUserName(user1);
        int i=1/0;
        User user2= new User();
        user2.setId(id);
        user2.setUsername(name2);
        userMapper.updateUserName(user2);
        return 1;
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();

    public int updateUserName(Integer id,String name1, String name2);
}
package com.yimeng;

import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获取bean并执行
        UserService userService = (UserService) ctx.getBean("userService");
        System.out.println("执行前:"+userService.findAll());
        try {
            userService.updateUserName(1,"梦一","一梦");
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println("错误了!");
        }
        System.out.println("执行前:"+userService.findAll());
    }
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yimeng.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!--注册Service的bean-->
    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
        <!--注入bean-->
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!--加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
        <property name="dataSource" ref="dataSource"/>
        <!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
        <property name="transactionFactory">
            <!--使用JdbcTransactionFactory进行事务管理-->
<!--            <bean class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>-->
            <!--使用SpringManagedTransactionFactory进行事务管理-->
            <bean class="org.mybatis.spring.transaction.SpringManagedTransactionFactory"/>
        </property>
    </bean>

    <!--spring 事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--默认事务超时时间-->
        <property name="defaultTimeout" value="30"/>
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--提交失败的话,也进行回滚-->
        <property name="rollbackOnCommitFailure" value="true"/>
    </bean>
    <!--开启声明式事务-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-spring
jdbc.username=root
jdbc.password=815924
<?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.yimeng.mapper.UserMapper">
    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

    <update id="updateUserName">
        update user set username=#{username} where id=#{id}
    </update>
</mapper>
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-spring-transaction</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

数据库:

image-20241027183213119

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241027182450937

这里好像并没有看到mybatis与spring事务整合的相关代码,事实上,这里对开发者屏蔽了

mybatis的jar包中自身提供了一个TransactionFactory接口和ManagedTransactionFactory、JdbcTransactionFactory。当通过mybatis-spring与spring进行整合后,spring中自带了另外一个TransactionFactory接口的实现SpringManagedTransactionFactory,spring集成mybatis默认使用的就是这个事务管理器。如下图:

img

SpringManagedTransactionFactory,顾名思义,作用就是讲事务委托给spring进行管理。

上面的内容中,我们多次讲到xml配置mybats,其中多次提到的SqlSessionFactoryBean中,就有一个transactionFactory属性,我们可以使用这个属性控制mybatis使用的事务管理器。比如,我们可以通过这个属性,让mybatis使用JdbcTransactionFactory事务管理器来管理事务(当然哈,在spring中还是建议使用SpringManagedTransactionFactory这个spring提供的事务管理器来进行事务管理)。

image-20241027183138439

很多情况下,我们不指定这个属性。如果没有指定的情况下,默认就是使用SpringManagedTransactionFactory来管理控制事务,相当于是把事务交给spring来管理。

img

注解版本
package com.yimeng.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;

@Configuration
@MapperScan(
        //等价于MapperScannerConfigurer的basePackage属性。扫描mapper接口的包路径,自动生成实现类。加上mapper包扫描,即basePackages属性,并且指定了markerInterface或者annotationClass,那么只有标记的接口自动生成实现类。但是,如果只写basePackages属性,不指定markerInterface或者annotationClass,那么这个包下的接口都会被自动生成实现类。
        basePackages = "com.yimeng.mapper",
//        //等价于MapperScannerConfigurer的markerInterface属性。自定义标记要生成实现类的接口。
//        markerInterface = YMMapperInterface.class,
//        //等价于MapperScannerConfigurer的annotationClass属性。使用mybatis的标记接口。
//        annotationClass = Mapper.class,
        //等价于MapperScannerConfigurer的sqlSessionFactoryBeanName属性
        sqlSessionFactoryRef = "sqlSessionFactory"
)
@EnableTransactionManagement // 启用声明式事务管理
public class DataBaseConfig {
    //定义数据源
    @Bean
    public DataSource dataSource() {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("815924");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring");
        dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
        return dataSource;
    }
    //定义SqlSessionFactoryBean
    @Autowired
    @Bean("sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setDataSource(dataSource);
        ssfb.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
        return ssfb;
    }

    // Spring 事务管理器
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        // 设置数据源
        transactionManager.setDataSource(dataSource);
        // 设置默认事务超时时间(单位:秒)
        transactionManager.setDefaultTimeout(30); // 设置为30秒
        // 提交失败时进行回滚
        transactionManager.setRollbackOnCommitFailure(true);
        return transactionManager;
    }
}
package com.yimeng.config;

// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

//@Mapper
//public interface UserMapper extends YMMapperInterface {
public interface UserMapper {
    public List<User> findAll();

    public int updateUserName(User user);
}
package com.yimeng.service.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
// @Autowired注解不需要手动写set方法
//    public void setUserMapper(UserMapper userMapper) {
//        this.userMapper = userMapper;
//    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUserName(Integer id, String name1, String name2) {
        User user1 = new User();
        user1.setId(id);
        user1.setUsername(name1);
        userMapper.updateUserName(user1);
        int i = 1 / 0;
        User user2 = new User();
        user2.setId(id);
        user2.setUsername(name2);
        userMapper.updateUserName(user2);
        return 1;
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();

    public int updateUserName(Integer id,String name1, String name2);
}
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
<?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.xsd">

<!--    &lt;!&ndash;注册Service的bean&ndash;&gt;-->
<!--    <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">-->
<!--        &lt;!&ndash;注入bean&ndash;&gt;-->
<!--        <property name="userMapper" ref="userMapper"/>-->
<!--    </bean>-->

    <!-- 扫描包。想要用注解@Service等bean的注解,那么就要使用这个扫描。 -->
    <context:component-scan base-package="com.yimeng"/>
</beans>
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

    <update id="updateUserName">
        update user set username=#{username} where id=#{id}
    </update>
</mapper>
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
    @Resource
    private UserService userService;
    @Test
    public void test(){
        System.out.println("执行前:"+userService.findAll());
        try {
            userService.updateUserName(1,"梦一","一梦");
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println("错误了!");
        }
        System.out.println("执行前:"+userService.findAll());
    }
}
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis-spring-transaction-anno</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <!--spring_mybatis桥梁-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241027235522072

分析1:@EnableTransactionManagement替代<tx:annotation-driven transaction-manager=“transactionManager”/>

image-20241027235633228

image-20241028001045343

分析2:看图就行。

image-20241027235742959

image-20241028001007294

spring整合mybatis的原理(简单介绍,自己的话)

简单的讲一下spring整合mybatis的原理。具体的可以看本文件夹的另一篇笔记《spring集成mybatis为什么不用写核心类》。

Mybatis的核心对象是SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession。spring集成mybatis其实底层也是使用这三个对象的,和不使用spring一样,都是靠这三个核心对象来完成最终效果的。

image-20241028214611134

上面spring集成mybatis的多种方式中,我就解析“Spring整合Mybatis方式四(非注解MapperScannerConfigurer)”的原理,这个比较好讲。

通过上面的学习,我们知道了,spring集成mybatis的时候,会注册一个id为sqlSessionFactory的bean给spring,一般我们使用的实现类是SqlSessionFactoryBean,所以这里先从SqlSessionFactoryBean开始讲。

image-20241028221041170

  1. SqlSessionFactoryBean类在成员变量中就创建了SqlSessionFactoryBuilder对象。这样后面就可以使用SqlSessionFactoryBuilder对象来创建SqlSessionFactory了。所以如果注入的sqlSessionFactory是单例的,那么SqlSessionFactoryBuilder也会是单例的(SqlSessionFactoryBuilder对象最好其实就是创建一次就行了)。

    image-20241028221115077

  2. SqlSessionFactoryBean实现了InitializingBean接口,并重写了afterPropertiesSet()方法,afterPropertiesSet()方法会在bean的设置到spring容器中的时候被自动被调用。并且在重写的afterPropertiesSet()方法中,完成了SqlSessionFactory对象的创建,以及相关配置文件和映射文件的解析操作。

    image-20241028221213226

    image-20241028221154689

    image-20241028221334757

    image-20241028221553641

  3. 并且这个类也实现了FactoryBean接口,并重写了getObject()方法,也就是说,从spring中获取bean的时候,其实是调用getObject方法返回的结果。这个getObject返回的结果,其实就是SqlSessionFactory对象(上面讲到的这个对象)。

    image-20241028221944431

    image-20241028222147504

  4. 所以传给MapperScannerConfigurer的就是SqlSessionFactoryBean的getObject方法返回的SqlSessionFactory对象。

    image-20241028222500599

  5. 接下来我们看MapperScannerConfigurer。MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口。BeanDefinitionRegistryPostProcessor 是BeanFactoryPostProcessor的子类,里面有一个postProcessBeanDefinitionRegistry()方法。实现了这个接口,Spring创建Bean之前会调用这个方法。我们去找到MapperScannerConfigurer类中的postProcessBeanDefinitionRegistry方法,这个方法才是真正被执行的方法。继续看,我们发现他看到调用了scane方法。scane方法调用了doScan方法,我们知道实际执行的时候是看真正创建的类的doScan方法,所以找到了ClassPathMapperScanner的doScan方法。这个doScan方法中看到调用了processBeanDefinitions方法。一个接口是没法创建实例对象的,所以这里创建对象之前将这个接口类型指向了一个具体的MapperFactoryBean类了,这样就可以创建出这个实例了(创建为实例才能使用这个实例创建出SqlSession)。也就是说,能扫描到的所有的Mapper接口,在容器里面都注册成一个MapperFactoryBean了。通过debug,我们可以看到确实是这样的。

    image-20241028222825670

    image-20241028222909481

    image-20241028223222183

    image-20241028223314444

    image-20241028223735087

    image-20241028223938047

    image-20241028224752452

    image-20241028224005400

    image-20241028225659009

    这也就正好解释了,为什么MapperScannerConfigurer能替代MapperFactoryBean了。

    image-20241028230221141

  6. 为什么要注册成MapperFactoryBean呢?首先来看看他们的类图结构

    image-20241028225842468

    从类图中我们可以看到MapperFactoryBean继承了SqlSessionDaoSupport,所以如果所有的mapper接口都被注册为MapperFactoryBean,那么他们都可以拿到SqlSessionTemplate对象了。然后我们还发现MapperFactoryBean实现了 FactoryBean接口,也就意味着,向容器中注入MapperFactoryBean对象的时候,本质上是把getObject方法的返回对象注入到了容器中。

    我们看一下这个getObject方法:

    image-20241028230344648

    发现其实,就是调用getMapper方法得到的代理对象了。我们注入到service层中的mapper对象,其实就是这个getObject(mapper接口名)拿到的代理对象。

  7. 我自己的一个猜测:在注册为MapperFactoryBean的时候,一些属性值已经被绑定上去了。比如说这个this.getSqlSession(),点进去看到是sqlSessionTemplate,但是这个sqlSessionTemplate什么时候被赋值的,我没有注意到,所以,我想,这个一定是在把mapper注册为MapperFactoryBean并实例化后,在某个我没有看到的角落偷偷地把对应的值绑定上去的,并且很有可能是利用xml中配置的sqlSessionFactory去创建出sqlSessionTemplate并且绑定到MapperFactoryBean的属性中去的。

    image-20241028232415561

    image-20241028232741132

    image-20241028232900778

如果看完我上面简单介绍的spring整合mybatis的原理还是不怎么理解,那么可以去看看这三篇写得比较好的文章:https://blog.csdn.net/tianshouzhi/article/details/103922850、https://blog.csdn.net/m0_71777195/article/details/129224916、https://blog.csdn.net/qq_41301079/article/details/102231881

版本五:springboot集成mybatis

例子:

package com.yimeng.config;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisConfig {
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer=new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.yimeng.**.mapper");
        return  mapperScannerConfigurer;
    }
}
package com.yimeng.domain;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
}
package com.yimeng.mapper;

import com.yimeng.domain.User;
import java.util.List;

public interface UserMapper {
    public List<User> findAll();
}
package com.yimeng.service.impl;

import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }
}
package com.yimeng.service;

import com.yimeng.domain.User;
import java.util.List;

public interface UserService {
    public List<User> findAll();
}
package com.yimeng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootMybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisApplication.class, args);
    }
}
<?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.yimeng.mapper.UserMapper">

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
</mapper>
<?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>
        <typeAlias type="com.yimeng.domain.User" alias="user"/>
    </typeAliases>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis-spring
    username: root
    password: 815924
    type: com.alibaba.druid.pool.DruidDataSource

mybatis:
  # 加载全局的配置文件
  configLocation: classpath:mybatis/mybatis-config.xml
package com.yimeng;

import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
public class SpringbootMybatisApplicationTests {
    @Resource
    private UserService userService;

    @Test
    void findAll() {
        List<User> userList = userService.findAll();
        System.out.println(userList);
    }
}
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>springboot-mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>
</project>

sql:

/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `mybatis-spring`;

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `user` */

insert  into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

执行结果:

image-20241030223347722

分析1:

下面这两个bean在springboot集成mybatis中都没有看到声明。

image-20241030231838088

我们只看到了这些配置:

image-20241030223932626

那么springboot是怎么执行mybatis,并且可以成功的呢?

image-20241030224233463

image-20241030224618506

image-20241030231007300

解释一下:因为springboot内部引入的默认的配置类,默认的配置类设置的@ConditionalOnMissingBean,@ConditionalOnMissingBean注解的效果就是,如果你自己定义了这个bean,那么就用你定义的bean来放到spring中去,这里这个方法不会被执行,不会把这个方法返回的对象放到spring中去,但是如果你没有自己定义,那么就会用这个方法把对应的bean注册到spring中去。

这个默认提供方法注册bean的方法会去spring环境中拿属性作为对应的值,完成注册(springboot的yaml文件中配置的属性都是会被放到环境中去的,我们只要把mybatis需要属性配置绑定上值就行了,到时候起步依赖内部默认方法把bean注册到spring时,会自己去取对应的属性的,然后完成注册bean到spring中去。注意,我们一定要把属性值绑定的mybatis起步依赖需要的属性名上去才行,这是一种约定,我们只要按照mybatis起步依赖的使用约定去放对应的值就行了,他会自己来拿这个值完成注册的)。关于dataSource什么时候注入的,我们可以看DataSourceAutoConfiguration类(可以看上图),这里不展开讲了,总之效果也是,去环境中拿对应的属性,然后注入数据源Bean。

分析2:上面的起步依赖的配置中没有扫描,所以,这里我们需要自己写一个扫描的bean。替代之前把MapperScannerConfigurer这个bean放到spring。

image-20241030232530071

image-20241030232558612

更具体的分析可以看:https://blog.csdn.net/weixin_45511500/article/details/124571380

扩展:

因为mybatis起步依赖中的bean在发现你自己有注入对应的MapperScannerConfigurer和SqlSessionFactoryBean就不会创建bean放到spring中。所以就是说,你可以完全自己注入这两个bean,而不用起步依赖注入这两个bean。所以我们下面这样做也行:

image-20241030233629074

这里扩展这里的代码就变动了MybatisConfig和application.yaml

所以在这里只贴出这两个代码,其他代码还是和上面的“spring整合mybatis的原理”中的一样。

package com.yimeng.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.sql.DataSource;

@Configuration
public class MybatisConfig {
 @Bean
 public DataSource dataSource() {
     DruidDataSource dataSource = new DruidDataSource();
     dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
     dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring");
     dataSource.setUsername("root");
     dataSource.setPassword("815924");
     return dataSource;
 }

 @Bean
 public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
     SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
     factoryBean.setDataSource(dataSource);
     factoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
     return factoryBean;
 }

 @Bean
 public MapperScannerConfigurer mapperScannerConfigurer() {
     MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
     mapperScannerConfigurer.setBasePackage("com.yimeng.**.mapper");
     return mapperScannerConfigurer;
 }
}
#spring:
#  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://localhost:3306/mybatis-spring
#    username: root
#    password: 815924
#    type: com.alibaba.druid.pool.DruidDataSource
#
#mybatis:
#  # 加载全局的配置文件
#  configLocation: classpath:mybatis/mybatis-config.xml
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值