当前位置: 首页 > news >正文

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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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方法(当然你使用构造注入也行)。
//    @Autowiredprivate SqlSessionTemplate sqlSessionTemplate;public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSessionTemplate = sqlSessionTemplate;}@Overridepublic 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 {
//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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 {@Overridepublic 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;}@Overridepublic 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;}@Overridepublic List<User> findAll(){UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);return userMapper.findAll();}@Overridepublic 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;}@Overridepublic List<User> findAll() {return userMapper.findAll();}@Overridepublic 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 configurationPUBLIC "-//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方法不需要写
//    @Autowiredprivate SqlSessionTemplate sqlSessionTemplate;public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSessionTemplate = sqlSessionTemplate;}@Overridepublic 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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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;
//    }@Overridepublic 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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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 {@Autowiredprivate 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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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;@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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 configurationPUBLIC "-//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 {//定义数据源@Beanpublic 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 {@Autowiredprivate UserMapper userMapper;// 使用@Autowired注解,可以省略set方法
//    public void setUserMapper(UserMapper userMapper) {
//        this.userMapper = userMapper;
//    }@Overridepublic 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 configurationPUBLIC "-//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.xsdhttp://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 {@Resourceprivate UserService userService;@Testpublic 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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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.xsdhttp://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.xsdhttp://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.xsdhttp://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.xsdhttp://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.xsdhttp://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.xsdhttp://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 {//    @Autowiredprivate UserMapper userMapper;public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic 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 configurationPUBLIC "-//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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://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 {//定义数据源@Beanpublic 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 事务管理器@Beanpublic 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 {@Autowiredprivate UserMapper userMapper;
// @Autowired注解不需要手动写set方法
//    public void setUserMapper(UserMapper userMapper) {
//        this.userMapper = userMapper;
//    }@Overridepublic 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 configurationPUBLIC "-//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.xsdhttp://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 {@Resourceprivate UserService userService;@Testpublic 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 {@Beanpublic 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 {@Resourceprivate UserMapper userMapper;@Overridepublic 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 configurationPUBLIC "-//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.Driverurl: jdbc:mysql://localhost:3306/mybatis-springusername: rootpassword: 815924type: com.alibaba.druid.pool.DruidDataSourcemybatis:# 加载全局的配置文件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 {@Resourceprivate UserService userService;@Testvoid 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 {@Beanpublic 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;}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));return factoryBean;}@Beanpublic 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

相关文章:

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

mybatis从浅入深一步步演变分析 版本一&#xff1a;不使用代理&#xff08;非spring&#xff09; 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…...

Java阶段三02

第3章-第2节 一、知识点 面向接口编程、什么是spring、什么是IOC、IOC的使用、依赖注入 二、目标 了解什么是spring 理解IOC的思想和使用 了解IOC的bean的生命周期 理解什么是依赖注入 三、内容分析 重点 了解什么是spring 理解IOC的思想 掌握IOC的使用 难点 理解IO…...

【Linux】掌握库的艺术:我的动静态库封装之旅

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.什么是库1.2 认识动静态库1.2.1 动态库1.2.2…...

UE5动画控制 基础

素材 mixamo先去选择一个character 点击下载 就这个下载下来 然后选几个animation&#xff0c; 记得勾选 把动作下载了 without skin就是只要动作 然后把他们放在一个文件夹里先 UE里导入 找一个文件夹&#xff0c;直接拖拽进来那个character的fbx&#xff0c;默认配置就…...

流畅!HTMLCSS打造网格方块加载动画

效果演示 这个动画的效果是五个方块在网格中上下移动&#xff0c;模拟了一个连续的加载过程。每个方块的动画都是独立的&#xff0c;但是它们的时间间隔和路径被设计为相互协调&#xff0c;以创建出流畅的动画效果。 HTML <div class"loadingspinner"><…...

linux命令之top(Linux Command Top)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…...

数据结构-希尔排序(ShellSort)笔记

看动画理解 【数据结构】八大排序(超详解附动图源码)_数据结构排序-CSDN博客 一 基本思想 先选定一个整数gap&#xff0c;把待排序文件中所有记录分成gap个组&#xff0c;所有距离为gap的记录分在同一组内&#xff0c;并对每一组内的元素进行排序。 然后将gap逐渐减小重复上…...

Junit + Mockito保姆级集成测试实践

一、做好单测&#xff0c;慢即是快 对于单元测试的看法&#xff0c;业界同仁理解多有不同&#xff0c;尤其是在业务变化快速的互联网行业&#xff0c;通常的问题主要有&#xff0c;必须要做吗&#xff1f;做到多少合适&#xff1f;现在没做不也挺好的吗&#xff1f;甚至一些大…...

软件项目管理要点

一.项目管理 1.盈亏平衡分析 销售额固定成本可变成本税费利润 当利润为0的时候就是盈亏平衡点。 2.范围管理 范围定义的输入包括&#xff1a;项目章程、项目范围管理计划、组织过程资产、批准的变更申请。 3.时间管理 项目时间管理中的过程包括活动定义、活动排序、活动的资…...

ESP8266 连接 MQTT 服务器EMQX 连接MQTTX

目录 1.先用有一台自己的云服务器 2. 使用FinalShell连接阿里云云服务器ECS 3.安装宝塔 4.在云服务器打开8888端口 5.使用外网面板地址打开宝塔面板 6.安装Docker 7.下载emqx 8.打开emqxWeb 界面 9.下载MQTTX 10.EMQX加一个客户端 11.开始通信 12.加入单片机ESP8266 …...

Python中如何处理异常情况?

1、Python中如何处理异常情况&#xff1f; 在Python中&#xff0c;处理异常情况通常使用try/except语句。try语句块包含可能会引发异常的代码&#xff0c;而except语句块包含处理异常的代码。如果try块中的代码引发了异常&#xff0c;控制流将立即转到相应的except块。 以下是…...

openpnp - 在openpnp中单独测试相机

文章目录 openpnp - 在openpnp中单独测试相机概述笔记END openpnp - 在openpnp中单独测试相机 概述 底部相机的位置不合适, 重新做了零件&#xff0c;准备先确定一下相机和吸嘴的距离是多少才合适。 如果在设备上直接实验&#xff0c;那么拆装调整相机挺麻烦的。 准备直接在电…...

Spark窗口函数

1、 Spark中的窗口函数 窗口就是单纯在行后面加一个列 可以套多个窗口函数&#xff0c;但彼此之间不能相互引用&#xff0c;是独立的 窗口函数会产生shuffle over就是用来划分窗口的 (1) 分组聚合里面的函数&#xff0c;基…...

Idea、VS Code 如何安装Fitten Code插件使用

博主主页:【南鸢1.0】 本文专栏&#xff1a;JAVA 目录 ​编辑 简介 所用工具 1、Idea如何安装插件 1.idea下载插件 2.需要从外部下载然后在安装&#xff0c; 2、VS Code如何安装插件 总结 简介 Fitten Code是由非十大模型驱动的AI编程助手&#xff0c;它可以自动生成代…...

elasticsearch7.x在k8s中的部署

一、说明 二、思路 三、部署 1、建nfs服务器 2、建持久卷 3、部署elasticsearch 四、附件 ?pv.yaml内容 elasticsearch.yaml内容 一、说明 本文章内容主要的参考来源是https://www.cnblogs.com/javashop-docs/p/12410845.html&#xff0c;但参考文献中的elasticsearc…...

校园社团信息管理平台:Spring Boot技术实战指南

3系统分析 3.1可行性分析 通过对本校园社团信息管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本校园社团信息管理系统采用SSM框架&#xff0c;JAVA作…...

【Linux】从内核角度理解 TCP 的 全连接队列(以及什么是 TCP 抓包)

文章目录 概念引入理解全连接队列内核方面理解Tcp抓包方法注意事项 概念引入 我们知道&#xff0c;TCP的三次握手是由TCP协议 自动处理的&#xff0c;建立连接的过程与用户是否进行accept无关&#xff0c;accept()的作用主要是为当前连接创建一个套接字&#xff0c;用于进行后…...

太速科技-712-6U VPX飞腾处理器刀片计算机

6U VPX飞腾处理器刀片计算机 一、产品概述 该产品是一款基于国产飞腾FT-2000四核处理器或D2000八核处理器的高性能6U VPX刀片式计算机。产品提供了可支持全网状交换的高速数据通道&#xff0c;其中P1、P2均支持1个PCIe x16 Gen3或2个PCIe x8 Gen3或4个PCIe x4 Gen3总…...

深度学习(八) TensorFlow、PyTorch、Keras框架大比拼(8/10)

一、深度学习框架概述 深度学习框架在当今人工智能和机器学习领域中占据着至关重要的地位。其中&#xff0c;TensorFlow 由 Google 开发&#xff0c;自 2015 年发布以来&#xff0c;凭借其灵活的计算图、自动微分功能以及跨平台支持等特点&#xff0c;迅速成为主流深度学习框架…...

thinkphp中命令行工具think使用,可用于快速生成控制器,模型,中间件等

在使用tp框架的时候tp内置了一个think的命令行工具&#xff0c; 这个工具可以帮助我们快速的生成控制器&#xff0c;模型&#xff0c;中间件的代码。 这个工具就和laravel中的 artisan 的作用都差不多&#xff0c;只是名称不同而已。 tp中常用的命令行工具&#xff1a; 1. 快…...

Discourse 是否支持手机注册

Discourse 能不能使用手机进行注册&#xff1f; 功能总结 简答来说&#xff0c;Discourse 不能使用手机注册&#xff0c;Discourse 也没有提供这个功能。 这个功能多是需要 SSO 来实现。 比如说华为的那个社区&#xff0c;他们自己做了一个自己的用户管理 SSO&#xff0c;然…...

软件测试学习笔记丨Flask框架-请求与响应

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/23408 请求方法 from flask import Flaskapp Flask(__name__)app.route("/cases", methods["get"]) def get_case():return {"code": 0, "msg": &…...

【C++笔记】list结构剖析及其模拟实现

【C笔记】list结构剖析及其模拟实现 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】list结构剖析及其模拟实现前言一 .list的结构及其介绍1.1list的结构1.2list的使用1.3迭代器划分 二.list的模拟实现2.1 list结构…...

C#进阶1

C#进阶1 本文章主要介绍C#的进阶知识&#xff0c;如反射&#xff0c;特性.... 参考视频链接 原码 文章目录 C#进阶1反射步骤泛型反射调用方法 获取属性 特性特性的定义步骤扩展枚举练习 反射 在 C# 中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&a…...

PHP如何对输出进行转义

在PHP中&#xff0c;对输出进行转义是为了防止跨站脚本攻击&#xff08;XSS&#xff09;和其他安全问题。PHP提供了多种函数来对输出进行转义&#xff0c;这些函数根据输出的上下文&#xff08;如HTML、JavaScript、URL等&#xff09;而有所不同。以下是一些常用的转义函数及其…...

Windows 10 安装Docker踩过的坑和解决-31/10/2024

目录 环境版本 一、Docker Desktop双击启动没反应&#xff0c;open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified. 二、Docker Desktop运行run命令时显示错误HTTP code 500 并且错误大意是服务器拒绝访问 三、检测Docker是否可以正常使用…...

【应急响应】Linux植入恶意程序排查流程

文章目录 前言一、Linux入侵检查二、Linux系统被入侵/中毒有哪些现象三、Linux系统被入侵/中毒处置过程四、Linux安全防护措施五、服务器被GetShell渗透解决办法(案例)前言 本篇文章主要是以我们日常的运维工作中对Linux服务器进行安全检查,进一步介绍如何使用具体命令来对Li…...

微信小程序app.js里面onLaunch里面的函数比page里面的onshow里面的方法后执行

微信小程序app.js里面onLaunch里面的函数比page里面的onshow里面的方法后执行 我们在app.js里面执行登录时可以调用checkLoginReadyCallback wx.login({ success: (res) > { $api .login({ jsCode: res.code, }) .then((res1) > { wx.hideLoading(); if (res1.code 0) …...

斐波那契时间序列,精准捕捉市场拐点 MT4免费公式源码!

指标名称&#xff1a;斐波那契时间序列 版本&#xff1a;MT4 ver. 2.01 斐波那契时间序列是一种技术分析工具&#xff0c;通过将斐波那契数列&#xff08;如1, 2, 3, 5, 8, 13等&#xff09;应用于时间轴上&#xff0c;用于预测市场价格的时间周期拐点。斐波那契时间序列在股…...

计算机的错误计算(一百四十)

摘要 探讨 MATLAB 中函数 的计算精度。 从计算机的错误计算&#xff08;一百三十九&#xff09;知&#xff0c;对于对数运算&#xff0c;当真数在 1 附近时&#xff0c;计算机的输出会出现较大误差。为此&#xff0c;IEEE 754-2019 中专门定义有函数 其目的就是当自变量在 …...

搜索引擎费用/seo优化的技巧

DOM&#xff1a;文档对象模型 --树模型文档&#xff1a;标签文档&#xff0c;对象&#xff1a;文档中每个元素对象&#xff0c;模型&#xff1a;抽象化的东西 一&#xff1a;window&#xff1a; 属性&#xff08;值或者子对象&#xff09;&#xff1a;opener:打开当前窗口的源窗…...

东莞清洁服务网站建设/杭州seo网站优化

我已按照所有步骤操作&#xff0c;一切正常&#xff0c;直到我完成步骤&#xff1a;在命令行中输入以下命令;create database arc_logon;create database arc_characters;create database arc_world;这不是确切的地点&#xff0c;但在导游要求我之后不久&#xff1a;mysql -u r…...

创建一个公司网站需要多少钱/网站怎么做谷歌推广

环境&#xff1a;keil uversion3 知识点&#xff1a; 问&#xff1a;include<file>与include"file"的区别 答&#xff1a;include<file>优先到标准库中去搜索模块。 include"file"优先到自定义库中去搜索模块。 功能&#xff1a;led灯闪烁 步骤…...

福州网站制作设计/淘宝店铺运营推广

上一篇文章提到了Android系统的UI线程是一种带消息循环&#xff08;Looper&#xff09;机制的线程&#xff0c;同时Android也提供了封装有消息循环&#xff08;Looper&#xff09;的HandlerThread类&#xff0c;这种线程&#xff0c;可以绑定Handler()对象&#xff0c;并通过Ha…...

电商网站有哪些使用场景/扬州seo推广

STP STP全称为“生成树协议”&#xff08;Spanning Tree Protocol&#xff09;&#xff0c;是一种网络协议&#xff0c;用于在交换机网络中防止网络回路产生&#xff0c;保证网络的稳定和可靠性。它通过在网络中选择一条主路径&#xff08;树形结构&#xff09;&#xff0c;并…...

公司网站选择什么空间/温州seo结算

以下情况会出现表单重复提交 用户提交表单&#xff0c;提交完成后&#xff0c;使用功能键F5&#xff0c;会出现重复提交用户在提交表单时&#xff0c;出现网络延迟的问题&#xff0c;而用户以为是卡了&#xff0c;多次点击提交按钮&#xff0c;导致表单重复提交用户提交完表单…...