mybatis从浅入深一步步演变分析
版本一:不使用代理(非spring)
package com.yimeng.domain;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E
### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--加载属性文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境-->
<environments default="developement">
<environment id="developement">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
测试类:
package com.yimeng;
import com.yimeng.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
//查询操作
public void test1() throws IOException {
//获得核心配置文件。
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作
//指定使用名称空间为userMapper的映射配置文件下id为findAll的sql语句
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印数据
System.out.println("=========================");
System.out.println(userList);
System.out.println("=========================");
//释放资源
sqlSession.close();
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yimeng</groupId>
<artifactId>mybatis-nospring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
执行结果:
数据库内容:
数据库内容:
/*
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 */;
特点:
这个内容就讲这么多,因为不常用,可以演变为使用代理的版本。
注意:
如果把上面的mapper配置文件的namespace改变了,那么也需要把selectList方法的参数也改变了才行。(因为这种方式必须是要写为namespace.xml的方法名
)
必须要下面这样才行:
接口取消也是可以的:
版本二:优化版本一。把调用数据层的语句写在对应的地方
我们service层要使用mapper层的方法,去对数据库进行操作,那么我们如果也像上面测试方法中这样写(就把上面的test1方法中的语句当做是service层方法的语句就行了),那么service还要创建SqlSessionFactory、SqlSession等,就不应该写在这里了,service应该不需要知道具体怎么去访问数据库,他就想做到:“给一个mapper层一个参数,然后mapper给他返回对应的数据就行了,service不想要知道具体怎么去执行的。,数据层具体怎么去拿,他不想知道”。所以,我们应该把这些创建SqlSessionFactory、SqlSession等对象的语句放在mapper层。
所以优化如下:
package com.yimeng.domain;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/9/24 22:53
* @PackageName:com.yimeng.mapper
* @ClassName: UserMapper
* @Description: TODO
* @Version 1.0
*/
public interface UserMapper {
public List<User> findAll() throws IOException;
}
package com.yimeng.mapper.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/9/24 22:54
* @PackageName:com.yimeng.mapper.impl
* @ClassName: UserMapperImpl
* @Description: TODO
* @Version 1.0
*/
public class UserMapperImpl implements UserMapper {
public List<User> findAll() throws IOException {
//获得核心配置文件。
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session回话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行操作
//指定使用名称空间为userMapper的映射配置文件下id为findAll的sql语句
List<User> userList = sqlSession.selectList("userMapper.findAll");
//释放资源
sqlSession.close();
return userList;
}
}
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-nospring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-nospring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-nospring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yimeng</groupId>
<artifactId>mybatis-nospring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
配置文件:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E
### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--加载属性文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境-->
<environments default="developement">
<environment id="developement">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
测试代码(这里test1中的代码,你可以理解为就是service层中的代码):
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.mapper.impl.UserMapperImpl;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
public class MyBatisTest {
@Test
//查询操作
public void test1() throws IOException {
UserMapper userMapper = new UserMapperImpl();
List<User> userList = userMapper.findAll();
//打印数据
System.out.println("=========================");
System.out.println(userList);
System.out.println("=========================");
}
}
结果:
这样的做法,你就可以看到service层(上面的test1)中没有写怎么访问数据库的代码了,这样就符合我们的开发思维了。
版本三:使用代理(非spring)
mybatis动态代理的方式
上面这个版本中,还存在问题,每一个mapper类的方法中都需要写获取session对象的语句,并且mapper层实现类的方法中也要自己调用原生api,自己绑定xml中的sql,就很麻烦,并且很多东西都是按照固定死的一种规则去写的。比如,创建那些核心对象,这个步骤是死的。比如,根据接受值和放回值是什么,确定调用mybatis的哪个原生API,确定去执行哪个xml中的sql,这些语句虽然不是写死的,但是规则基本是固定的。既然这样,那么mybatis就想能不能自动给我们生成对应的代码,我们只要以某种约定告诉他对应的信息就行了。
mybatis确实实现了这个功能。只要我们根据mybatis的约定,提供给mybatis需要的信息,那么他就能自动给我们调用对应原生方法,去执行对应的sql,并封装到对应的类型中去返回给我们。
他是怎么做到的呢?其实就是通过JDK动态代理来实现的。
我们需要提供给他接口(不用提供实现类,mybatis底层自动用JDK动态代理给我们生成对应的实现类和实现类中的方法逻辑),接口的全限定名要对应的xml文件的namespace,并且接口中方法的方法名要和xml中要执行的sql的id一样。这样,mybatis才能自动根据他的约定去判断出要给我们生成的实现类是什么样的,对应的方法的功能是什么样的,我们调用接口中的方法应该去执行哪个sql。其实他就是通过接口提供mybatis需要的信息的,再自动给我们生成对应的实现类的,当然哈,接口必须要告诉给mybatis(必须扫描接口)。接口是通过mybatis的配置文件来告诉mybatis的(通过注解也行,注解和配置文件来告诉mybatis要动态代理哪些接口,这两种方式其实都是一样的,只是方法论不同而已,思想都是一样的,注解底层也是代码,只是封装了一下而已):
扫描的语句:
好,现在我们演示一下mybatis的动态代理。
这里我们先把上面这个代码改造掉去,简单地使用代理,看看怎么使用的。
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/9/24 22:53
* @PackageName:com.yimeng.mapper
* @ClassName: UserMapper
* @Description: TODO
* @Version 1.0
*/
public interface UserMapper {
public List<User> findAll() throws IOException;
}
package com.yimeng.domain;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-nospring
jdbc.username=root
jdbc.password=815924
### 设置日志级别-如需更详细的日志记录,请将“info”更改为“debug” ###
log4j.rootLogger=debug, stdout, D, E
### 将日志消息直接发送到stdout(日志输出到标准输出(控制台)) ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出DEBUG级别以上的日志到 D://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
### 输出ERROR级别以上的日志到 E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %C.%M(%L) - %m%n
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--加载属性文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境-->
<environments default="developement">
<environment id="developement">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisTest {
@Test
//查询操作
public void test1() throws IOException {
//获得核心配置文件。
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
//打印数据
System.out.println("=========================");
System.out.println(userList);
System.out.println("=========================");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yimeng</groupId>
<artifactId>mybatis-nospring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
数据库:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-nospring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-nospring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-nospring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
结果:
解释:
这里我们把上面版本二中的代码修改了,看到我们没有写mybatis实现类。
虽然我们没有写实现类,但是我们通过sqlSession.getMapper(对应接口.class)
好像还是获取到了UserMapper接口的实现类实例了,其实这个实现类实例就是mybatis给我们动态创建的动态代理对象。
相比于上个版本的代码,我们这里又在service(这里的test1)中写了获取mybatis核心对象的语句了,但是没有关系,这个等到结合spring我们就可以把这些语句交给spring来做了,那样service就又不需要写这些步骤了。
其实包括下面的sqlSession.getMapper(接口.class)这一步,我们都可以交给spring,我们只要在service层注入UserMapper就行了,注入进来的其实就是这里sqlSession.getMapper(接口.class)获取到的代理对象,service层只要直接用这个代理对象就行了,不需要知道怎么创建的。
其实mybatis动态代理的核心就是这个getMapper(接口.class)
方法了,如果感兴趣可以自己去阅读源码,这里不展开说具体是怎么做到创建这个代理对象的。
其实mybatis就是在上面的sqlSession.getMapper()方法中进行了动态代理的。
如果想要了解更细,那么可以看sqlSession.getMapper()方法的源码。
mybatis中的动态代理
mybatis虽然使用了动态代理,但是并不是动态代理的常规用法。动态代理可以分为两种,一种是有实现类的,一种是没有实现类的(mybatis使用的就是没有实现类的这种方式),有实现类的那种动态代理,一般的使用是既执行实现类的方法,又执行一些增强的逻辑。没有实现类的效果是,只有增强,没有执行原有实现类的方法(因为都没有实现类)。
大概的效果类似下面这样的代码:
mybatis中动态代理的增强效果是:“通过一系列的信息,然后自动判断出要执行mybatis原生的哪一个API,并把对应的结果返回!”。
这里怎么判断方法是查询一个、查询多个、插入、修改、删除的呢?是通过标签(select、update、delete、insert)或者sql吗?我觉得不是,我觉得他可能有一个内部自己的判断逻辑。因为我试了,在xml中的delete、update的标签内写insert into语句,发现也成功插入的,在insert、update标签内写delete语句,也能删除成功。但是在select标签内写insert into却没有插入成功。
具体的原因我不知道,我不知道这里它是怎么判断执行那个方法的,但是不重要了。反正,我们按照它的规范来写就行了,只要是插入的sql,就写insert标签,只要是update标签,那么就写更新的sql,这样,结果就肯定是我们所想当然的结果了。
值得注意的是:INSERT…ON DUPLICATE KEY UPDATE这种可能是更新,也可能是插入的sql怎么写呢?
这个随便你写insert标签或者update标签都行。
有人可能会问为什么?上面不是说了了嘛!(上面说了"我试了,在xml中的delete、update的标签内写insert into语句,发现也成功插入的,在insert、update标签内写delete语句,也能删除成功……")
INSERT…ON DUPLICATE KEY UPDATE这种其实谁都不好确定是更新或者是插入,所以,也难以通过mybatis的使用规则来确定使用insert还是update标签,但是不重要,使用insert或者update标签,执行都是正确的。就和上面我们说的,在delete、update的标签内写insert into语句也能成功一样,所以我猜想mybatis的select、update、delete、insert标签可能规则是这样的:如果是能影响数据行数的,你使用insert、delete、update标签都行,就是不能使用select标签。
注意:mybatis使用的是jdk动态代理。是基于接口的动态代理。
不写实现类的动态代理怎么写?请看同文件夹下《代理模式》的笔记!
版本四:结合spring的版本
Spring 整合 Mybatis 方式一(非注解、SqlSessionTemplate)
使用配置文件
在mybatis与spring整合后, 通常我们不会直接使用SqlSessionFactory,因为这种方式用起来比较麻烦。
mybatis-spring提供了易于使用的类,如SqlSessionTemplate、SqlSessionDaoSupport等。
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.mapper.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
// 如果通过 @Autowired进行注入,那么set方法不需要写。但是这里使用xml注入,所以需要提供这个set方法(当然你使用构造注入也行)。
// @Autowired
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> findAll(){
// 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!-- <environments default="developement">-->
<!-- <environment id="developement">-->
<!-- <transactionManager type="JDBC"/>-->
<!-- <dataSource type="POOLED">-->
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </dataSource>-->
<!-- </environment>-->
<!-- </environments>-->
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注册mapper的bean-->
<bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
<!--注入bean-->
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-integrate-sping</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
数据库数据:
执行结果:
细心的读者注意到,在mybatis-config.xml文件中并没有配置、、等元素。因为mybatis-config.xml文件中即使配置了这些标签,也会被SqlSessionFactoryBean忽略。这里的这种方式使用mybatis我们需要显式的为SqlSessionFactoryBean的dataSource属性注入对应Bean才行,如果不是这样做的话,项目在其初始化时就会抛出异常。
比如:
注意:上面这个spring集成mybatis写的mybatis-config.xml是放到SqlSessionFactoryBean中的一些配置信息。而之前我们写的mybatis在非spring下的时候中,写的那个sqlMapConfig.xml和这里这个配置是不一样的。
虽然写的内容你看起来是类似的,但是其实不是一个东西。之前sqlMapConfig.xml配置文件的时候是SqlSessionFactoryBuilder创建SqlSessionFactory对象需要的,这里我们写的配置文件是SqlSessionFactoryBean对象需要的。他们两个不是一个东西,所以能写的东西也不是完全一样的(虽然有部分内容是完全一样的写法的)。
使用不同的东西,用法也不同,这个是可以理解的,你也知道,我们去写一个代码去完成一样的东西,但是实现方式肯定也不止一种。不同实现方式使用起来的规则肯定也是不一样的,所以没有必要纠结为什么这里两种配置方式为什么不一样,没必要纠结实现这个某个的方法论为什么不同,去实现一个目标走不同的路是很正常的。
mybatis集成spring和不集成spring的一部分区别
区别1
没有使用spring的时候,是用的DefaultSqlSession获取代理对象的。
使用spring的时候,是用的SqlSessionTemplate获取代理对象的。
所以还是有一些不同的。
不管是DefaultSqlSession还是SqlSessionTemplate都是其实都是我们说的Sqlsession,你看他们都是实现了SqlSession接口。
但是注意哈,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 */;
不使用spring,并且没有进行提交事务的插入(删除、修改也是类似的,这里就演示新增):
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
public int insertUser(User user);
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserServiceImpl implements UserService {
@Override
public List<User> findAll() throws IOException {
//获得核心配置文件。
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
sqlSession.close();
return userList;
}
@Override
public int insertUser(User user) throws IOException {
//获得核心配置文件。
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int row = userMapper.insertUser(user);
// 要提交才行。不然插入无效。
// sqlSession.commit();
sqlSession.close();
return row;
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.io.IOException;
import java.util.List;
public interface UserService {
public List<User> findAll() throws IOException;
public int insertUser(User user) throws IOException ;
}
package com;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import com.yimeng.service.impl.UserServiceImpl;
import java.io.IOException;
/**
* @Author yimeng
* @Date 2024/10/20 0:51
* @PackageName:com
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) throws IOException {
UserService userService = new UserServiceImpl();
System.out.println("插入前查询:"+userService.findAll());
User user = new User();
user.setUsername("test");
user.setPassword("123456");
userService.insertUser(user);
System.out.println("插入后查询:"+userService.findAll());
}
}
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-spring-contrast
jdbc.username=root
jdbc.password=815924
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--加载属性文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境-->
<environments default="developement">
<environment id="developement">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
<insert id="insertUser">
INSERT INTO user(username,password) VALUES (#{username},#{password})
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-nospring-contrast</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
</dependencies>
</project>
执行结果:
加上提交事务后,执行的结果(和上面代码的不同就只是这里执行打开了sqlSession.commit();注释而已,所以就不贴代码了):
看到提交事务就成功插入了,看来没有集成spring的mybatis中是手动提交事务才行的(当然哈,你使用openSession(ture)也行,开启自动提交事务,如果没有开启自动提交事务,那么就必须手动提交事务了)。
在spring版本下的mybatis:
数据库还是继续用上面的数据哈。
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String password;
}
package com.yimeng.mapper.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> findAll(){
UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
return userMapper.findAll();
}
@Override
public int insertUser(User user){
UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
return userMapper.insertUser(user);
}
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
public int insertUser(User user);
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
public int insertUser(User user){
return userMapper.insertUser(user);
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
public int insertUser(User user);
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
System.out.println("插入前查询:"+userService.findAll());
User user = new User();
user.setUsername("spring");
user.setPassword("123456");
userService.insertUser(user);
System.out.println("插入后查询:"+userService.findAll());
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!-- <environments default="developement">-->
<!-- <environment id="developement">-->
<!-- <transactionManager type="JDBC"/>-->
<!-- <dataSource type="POOLED">-->
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </dataSource>-->
<!-- </environment>-->
<!-- </environments>-->
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注册mapper的bean-->
<bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
<!--注入bean-->
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring-contrast"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
<insert id="insertUser">
INSERT INTO user(username,password) VALUES (#{username},#{password})
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-spring-contrast</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
执行结果:
所以,看到在spring整合mybatis中使用mybatis,没有手动提交事务,也没有去手动开启自动提交,结果也是可以成功进行插入的。(PS:可能在SqlSessionTemplate内部已经进行开启了自动提交了!所以这里不用显示开启自动提交也可以做到执行完毕就影响数据库。)
不使用配置文件(不抽取mybatis-config.xml)
例子:
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
// 如果通过 @Autowired进行注入,那么set方法不需要写
// @Autowired
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> findAll(){
// 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
return userMapper.findAll();
}
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注册mapper的bean-->
<bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
<!--注入bean-->
<property name="sqlSessionTemplate" ref="sqlSession"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!-- <!–通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。–>-->
<!-- <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 */;
数据库:
执行结果:
解释:从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之前的做法:
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中引入这个配置文件):
当然,使用mybatis配置文件和不使用mybatis配置文件的做法都是可以的,看你喜欢。
Spring 整合 Mybatis 方式二(非注解、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.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
// // 如果通过 @Autowired进行注入,那么set方法不需要写
@Autowired
// private SqlSessionTemplate sqlSessionTemplate;
//
// public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
// this.sqlSessionTemplate = sqlSessionTemplate;
// }
@Override
public List<User> findAll(){
// 相当于对方法封装了一层,用户在使用的时候可以直接调用,不需要再创建SqlSession。获取代理对象。
// UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
UserMapper userMapper = getSqlSession().getMapper(UserMapper.class);
return userMapper.findAll();
}
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!-- <environments default="developement">-->
<!-- <environment id="developement">-->
<!-- <transactionManager type="JDBC"/>-->
<!-- <dataSource type="POOLED">-->
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </dataSource>-->
<!-- </environment>-->
<!-- </environments>-->
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注册mapper的bean-->
<bean id="userMapper" class="com.yimeng.mapper.impl.UserMapperImpl">
<!--注入bean-->
<!-- <property name="sqlSessionTemplate" ref="sqlSession"/>-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
<!-- 使用SqlSessionDaoSupport就可以不用写这个SqlSessionTemplate了。之前写这个SqlSessionTemplate是因为mapper实现类中需要注入这个。上面UserMapperImpl中注入了sqlSessionFactory就行了。内部可能自己创建了SqlSessionTemplate。-->
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!-- <constructor-arg ref="sqlSessionFactory"/>-->
<!-- </bean>-->
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-integrate-spring2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
数据库数据:
执行结果:
sqlSessionDapSupport其实就是对sqlSessionTemplate 又封装了一次而已。
为什么注入sqlSessionFactory?
补充:其实继承SqlSessionDaoSupport的类你给他一个sqlSessionFactory 或 sqlSessionTemplate 属性都行的,虽然上面我只展示了sqlSessionFactory 属性哈。如果两者都被设置了 , 那么SqlSessionFactory是被忽略的。
原因:
我们看到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方法所返回的对象。
Spring整合Mybatis方式三(非注解、MapperFactoryBean)
无论是使用SqlSessionTemplate,还是继承SqlSessionDaoSupport,我们都需要手工编写DAO类的代码,手动使用getMapper()方法获取代理对象,然后调用对应的方法。
但是在与spring进行整合时,是否有更加简单的使用方法呢?能否通过@Autowired注解或者spring配置文件直接注入Mapper呢?
我们期望的使用方式是这样:
public class UserService {
@Autowired
private UserMapper userMapper;
public void insert(User user){
userMapper.insert(user);
}
}
或者在spring的xml中配置,再直接:
public class UserService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public void insert(User user){
userMapper.insert(user);
}
}
在没有进行任何配置的情况下,直接这样操作显然是会报错的,因为UserMapper是一个接口,且不是spring管理的bean,因此无法直接注入。
所以应该怎么做呢?直接看下面操作就行了。这里只展示使用xml的方式配置bean。
例子:
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!-- <environments default="developement">-->
<!-- <environment id="developement">-->
<!-- <transactionManager type="JDBC"/>-->
<!-- <dataSource type="POOLED">-->
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </dataSource>-->
<!-- </environment>-->
<!-- </environments>-->
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
<!-- 这里没有mapper实现类,所以也没有注入SqlSessionTemplate属性。自动生成实现类,他内部就自动用了SqlSessionTemplate,所以不需要我们手动来注册这个bean了。-->
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!-- <constructor-arg ref="sqlSessionFactory"/>-->
<!-- </bean>-->
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-mapperFactoryBean</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
数据库:
执行结果:
这里我们看到,使用了
<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:
SqlSessionDaoSupport:
Spring整合Mybatis方式四(非注解MapperScannerConfigurer)
通过MapperFactoryBean配置,已经是mybatis与spring进行时理想的方式了,我们可以简单的通过@Autowired注解或者spring的配置文件进行注入。
但是如果有许多的Mapper接口要配置,针对每个接口都配置一个MapperFactoryBean,会使得我们的配置文件很臃肿。关于这一点,mybatis-spring包中提供了MapperScannerConfigurer来帮助你解决这个问题。
MapperScannerConfigurer可以指定扫描某个包,然后为这个包下的所有Mapper接口都自动生成实现类,效果和把这个扫描的包下所有的接口都用MapperFactoryBean注册为spring的bean
一样。
例子:
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @Author yimeng
* @Date 2024/10/18 16:38
* @PackageName:com.yimeng
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境(在spring中,你的数据源得注入成bean在给SqlSessionFactoryBean).在这里写没有用.-->
<!-- <environments default="developement">-->
<!-- <environment id="developement">-->
<!-- <transactionManager type="JDBC"/>-->
<!-- <dataSource type="POOLED">-->
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </dataSource>-->
<!-- </environment>-->
<!-- </environments>-->
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!-- <property name="mapperInterface" value="com.yimeng.mapper.UserMapper" />-->
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<!-- </bean>-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
<!--其他配置-->
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
<!-- 这里没有mapper实现类,所以也没有注入SqlSessionTemplate属性。自动生成实现类,他内部就自动用了SqlSessionTemplate,所以不需要我们手动来注册这个bean了。-->
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">-->
<!-- <constructor-arg ref="sqlSessionFactory"/>-->
<!-- </bean>-->
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-mapperScannerConfigurer</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
执行结果:
和上面使用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>
注意:basePackage 属性是用于指定Mapper接口的包路径。如果的Mapper接口位于不同的包下,可以使用分号”;”或者逗号”,”进行分割。
比如:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="aa.bb.mapper;aa.dd.mapper" />
</bean>
如果某个路径还包含子包,子包中的Mapper接口递归地被搜索到。因此对于上述配置,我们可以通过公共的包名进行简化。如:
<property name="basePackage" value="aa" />
你可能想到了,如果指定的公共的包名下面还包含了一些其他的接口,这些接口是你作为其他用途使用到的,并不能作为mybatis的Mapper接口来使用。此时,你可以通过markerInterface属性或者annotationClass属性来进行过滤。
markerInterface属性,顾名思义,通过定义一个标记接口(接口中不需要定义任何方法),来对Mapper映射器接口进行过滤,如:
public interface MapperInterface{}
接着,你需要将你的映射器接口继承MapperInterface,如:
public interface UserMapper extends MapperInterface{
public void insert(User user);
}
此时你可以为MapperScannerConfigurer指定只有继承了MapperInterface接口的子接口,才为其自动注册MapperFactoryBean,如:
<property name="markerInterface" value=“com.tianshouzhi.mybatis.MybatisMapperInterface"/>
annotationClass属性的作用是类似的,只不过其是根据注解进行过滤。你不需要自定义注解,mybatis已经提供了一个@Mapper注解,你直接使用即可。配置如下:
<property name="annotationClass" value="org.apache.ibatis.annotations.Mapper"/>
下面演示一下多个mapper的例子:
package com.yimeng.config;
// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class Dept {
private int id;
private String name;
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class Role {
private int id;
private String name;
private String description;
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.Dept;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DeptMapper extends YMMapperInterface {
List<Dept> getAllDepartments();
}
package com.yimeng.mapper;
import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper extends YMMapperInterface {
public List<User> findAll();
}
package com.yimeng.mapper2;
import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.Role;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface RoleMapper extends YMMapperInterface {
List<Role> getAllRoles();
}
package com.yimeng.service.impl;
import com.yimeng.domain.Dept;
import com.yimeng.mapper.DeptMapper;
import com.yimeng.service.DeptService;
import java.util.List;
public class DeptServiceImpl implements DeptService{
private DeptMapper deptMapper;
@Override
public List<Dept> getAllDepartments(){
return deptMapper.getAllDepartments();
}
public void setDeptMapper(DeptMapper deptMapper) {
this.deptMapper = deptMapper;
}
}
package com.yimeng.service.impl;
import com.yimeng.domain.Role;
import com.yimeng.mapper2.RoleMapper;
import com.yimeng.service.RoleService;
import java.util.List;
public class RoleServiceImpl implements RoleService {
private RoleMapper roleMapper;
public void setRoleMapper(RoleMapper roleMapper) {
this.roleMapper = roleMapper;
}
@Override
public List<Role> getAllRoles(){
return roleMapper.getAllRoles();
}
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.Dept;
import java.util.List;
public interface DeptService {
List<Dept> getAllDepartments();
}
package com.yimeng.service;
import com.yimeng.domain.Role;
import com.yimeng.domain.User;
import java.util.List;
public interface RoleService {
List<Role> getAllRoles();
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.Dept;
import com.yimeng.domain.Role;
import com.yimeng.domain.User;
import com.yimeng.mapper.DeptMapper;
import com.yimeng.service.DeptService;
import com.yimeng.service.RoleService;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
// 获取bean并执行
DeptService deptService = (DeptService) ctx.getBean("deptService");
List<Dept> allDepartments = deptService.getAllDepartments();
System.out.println(allDepartments);
// 获取bean并执行
RoleService roleService = (RoleService) ctx.getBean("roleService");
List<Role> allRoles = roleService.getAllRoles();
System.out.println(allRoles);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
<typeAlias type="com.yimeng.domain.Dept" alias="dept"/>
<typeAlias type="com.yimeng.domain.Role" alias="role"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
<mapper resource="DeptMapper.xml"/>
<mapper resource="RoleMapper.xml"/>
</mappers>
</configuration>
注意:下面这里的xml中写了四种mapper接口的扫描方式,你想要试一下哪一种就打开对应的注释就行了。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--下面四种自动生成实现类的做法都是可以的,随便打开一种方式的注释,执行都是成功的。你选一个自己喜欢的就行了。其中方式一的做法最麻烦,需要给每一个要让mybatis自动生成实现类的接口都注册一遍。其他三种方式都是蛮方便的。其中第四中方式中,需要在mapper接口上面加上@Mapper注解,作为标记,这样mybatis知道要把basePackage下的这些接口进行自动生成实现类。其中第三种做法,我们就需要自己定义一个接口,接口随便叫都行,然后让需要自动生成实现类的mapper接口们都继承这个接口,最后告诉mybatis,标记的接口叫什么名字。其实,只要符合规范,第二种做法就是最简单的,我们只要约定,把mapper接口都放在指定包下就行了,这样我们都不用标记。-->
<!--自动生成实现类方式四。-->
<!--使用@Mapper注解来标记要让mybatis自动生成实现类的接口也行。需要做到在每一个mapper接口上面加上@Mapper注解。不要忘了,这个basePackage写的包名是这几个mapper公共包哈。在公共包下,不需要让mybatis生成实现类的那些接口就不用加上@Mapper注解了。使用接口标记的方式不需要加@Mapper注解哈。接口标记和@Mapper注解标记要让mybatis生成的实现类都行,你二选一就行了。接口标记法,接口是要你自己定义的。但是@Mapper是不需要你自己定义注解的,这个@Mapper是mybatis自带的。-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng" />
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--使用Mapper注解来标记要让mybatis自动生成实现类的接口也行。-->
<property name="annotationClass" value="org.apache.ibatis.annotations.Mapper"/>
</bean>
<!--自动生成实现类方式三。-->
<!--扫描是包括扫描子包的,所以,下面的做法,我们可以用这个方式来做。-->
<!--如果指定的公共的包名下面还包含了一些其他的接口,这些接口是你作为其他用途使用到的,并不能作为mybatis的Mapper接口来使用,那么我们可以通过通过markerInterface属性或者annotationClass属性来进行过滤。当然,不过滤也行,倒是不会直接报错,只是会给你警告,不影响运行。-->
<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">-->
<!-- <property name="basePackage" value="com.yimeng" />-->
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!-- <!–告诉mybatis,只有继承YMMapperInterface接口的接口,才让mybatis自动生成实现类。–>-->
<!-- <property name="markerInterface" value="com.yimeng.config.YMMapperInterface"/>-->
<!-- </bean>-->
<!--自动生成实现类方式二。-->
<!--扫描包的话,就可以替代给每一个mapper写MapperFactoryBean了。可以代替下面那个注释掉的写法。如果有多个包要扫描,那么使用;或者,分开就行。-->
<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">-->
<!--<!– <property name="basePackage" value="com.yimeng.mapper;com.yimeng.mapper2" />–>-->
<!-- <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>
数据库数据:
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 */;
执行结果:
Spring整合Mybatis方式五(注解的方式@MapperScan)
如果读者习惯使用注解,而不是xml文件的方式进行配置,mybatis-spring提供了@MapperScan注解,其可以取代MapperScannerConfigurer。
一些读者可能在springboot中也使用过@MapperScan注解,那个是springboot启动类提供的注解。这里我们要用的**@MapperScan注解是mybatis-spring中提供的,并不是mybatis-springboot-starter中提供的**。这一点值得注意,不要导错包了。
以下演示了如何通过@MapperScan注解的方式来配置mybatis与spring整合,注解中的属性可以与MapperScannerConfigurer相对应。
package com.yimeng.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import javax.sql.DataSource;
@Configuration
@MapperScan(
//等价于MapperScannerConfigurer的basePackage属性。扫描mapper接口的包路径,自动生成实现类。加上mapper包扫描,即basePackages属性,并且指定了markerInterface或者annotationClass,那么只有标记的接口自动生成实现类。但是,如果只写basePackages属性,不指定markerInterface或者annotationClass,那么这个包下的接口都会被自动生成实现类。
basePackages = "com.yimeng.mapper",
// //等价于MapperScannerConfigurer的markerInterface属性。自定义标记要生成实现类的接口。
// markerInterface = YMMapperInterface.class,
// //等价于MapperScannerConfigurer的annotationClass属性。使用mybatis的标记接口。
// annotationClass = Mapper.class,
//等价于MapperScannerConfigurer的sqlSessionFactoryBeanName属性
sqlSessionFactoryRef = "sqlSessionFactory"
)
public class DataBaseConfig {
//定义数据源
@Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setUsername("root");
dataSource.setPassword("815924");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring");
dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
return dataSource;
}
//定义SqlSessionFactoryBean
@Autowired
@Bean("sqlSessionFactory")
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setDataSource(dataSource);
ssfb.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
return ssfb;
}
}
package com.yimeng.config;
// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.config.YMMapperInterface;
import com.yimeng.domain.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
//@Mapper
//public interface UserMapper extends YMMapperInterface {
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// 使用@Autowired注解,可以省略set方法
// public void setUserMapper(UserMapper userMapper) {
// this.userMapper = userMapper;
// }
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import org.springframework.stereotype.Service;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <!–注册Service的bean–>-->
<!-- <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">-->
<!-- <!–注入bean–>-->
<!-- <property name="userMapper" ref="userMapper"/>-->
<!-- </bean>-->
<!-- 扫描包。想要用注解@Service等bean的注解,那么就要使用这个扫描。 -->
<context:component-scan base-package="com.yimeng"/>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
@Resource
private UserService userService;
@Test
public void test(){
List<User> userServiceAll = userService.findAll();
System.out.println(userServiceAll);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-spring-annotate</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
执行结果:
分析1:
这里的案例中把上面“Spring整合Mybatis方式四(非注解MapperScannerConfigurer)”的basePackage、sqlSessionFactory、annotationClass、markerInterface都替代了。
注意:上面注解中说替代的sqlSessionFactoryBeanName和sqlSessionFactory属性不是一样的。这个等一下讲。这里你就认为注解写法的sqlSessionFactoryRef是替代xml中的sqlSessionFactory的就行了。(其实他们的关系是:在xml中sqlSessionFactoryBeanName是替代sqlSessionFactory的,因为使用sqlSessionFactory可能会出现问题,而注解写法中的sqlSessionFactoryRef属性是替代xml中MapperScannerConfigurer的sqlSessionFactoryBeanName属性的。关于MapperScannerConfigurer的sqlSessionFactoryBeanName属性等一下讲。)
分析2:
注解的写法中替代数据源和sqlSessionFactory这个bean的注入。
分析3:
注意:配置信息抽取的问题(MapperScannerConfigurer注入sqlSessionFactory和sqlSessionTemplate属性会出现的问题)
注意:MapperScannerConfigurer的sqlSessionFactory和sqlSessionTemplate属性已经不建议使用了。原因在于,这两个属性不支持你使用spring提供的PropertyPlaceholderConfigurer的属性替换。
例如:你配置了SqlSessionFactoryBean来创建SqlSessionFactory实例,前面已经看到必须为其指定一个dataSource属性。很多用户习惯将数据源的配置放到一个独立的配置文件,如jdbc.properties文件中,之后在spring配置中,通过占位符来替换,如:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
对于这样的配置,spring在初始化时会报错,因为MapperScannerConfigurer会在PropertyPlaceholderConfigurer初始化之前,就加载dataSource的配置,而此时PropertyPlaceholderConfigurer还未准备好替换的占位符的内容,所以抛出异常。
演示一下之前的例子(之前使用MapperScannerConfigurer扫描的例子):
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
System.out.println("UserService的findAll方法执行 ...");
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!-- <property name="sqlSessionTemplate" ref="sqlSession"/>-->
<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
<!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- 注入数据源。使用druid来配置数据源。-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>
<property name="username" value="root"/>
<property name="password" value="815924"/>
</bean>
<!-- <!–加载外部的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>
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 */;
执行结果:
现在是正常的。
但是如果我们使用抽取的数据源呢?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!-- <property name="sqlSessionTemplate" ref="sqlSession"/>-->
<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
<!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- <!– 注入数据源。使用druid来配置数据源。–>-->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </bean>-->
<!--加载外部的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>
执行结果:
原因是:MapperScannerConfigurer会在PropertyPlaceholderConfigurer初始化之前,就加载dataSource的配置,而此时PropertyPlaceholderConfigurer还未准备好替换的占位符的内容,所以抛出异常。
解决方案:
我们可以使用另外属性来替代:
- sqlSessionFactoryBeanName替代sqlSessionFactory属性。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!-- <property name="sqlSessionTemplate" ref="sqlSession"/>-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>-->
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- <!– 注入数据源。使用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>-->
<!--加载外部的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>
如果你之前不是用sqlSessionFactory的,而是用sqlSessionTemplate的(MapperScannerConfigurer中写sqlSessionFactory和sqlSessionTemplate都是可以的,注入任何一个都行),也是同理,可以使用sqlSessionTemplateBeanName代替sqlSessionTemplate属性。
即,注入sqlSessionFactory和sqlSessionTemplate的效果是一样的。sqlSessionTemplateBeanName是替代sqlSessionTemplate解决占位符问题的。sqlSessionFactoryBeanName是替代sqlSessionFactory属性解决占位符问题的。
下面也展示一下具体的使用:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<property name="sqlSessionTemplate" ref="sqlSession"/>
<!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
<!--<property name="sqlSessionTemplateBeanName" value="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>
<!-- <!–加载外部的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>
执行结果:
看到是可以的。
如果我们使用抽取的数据源会怎么样呢?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<property name="sqlSessionTemplate" ref="sqlSession"/>
<!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
<!--<property name="sqlSessionTemplateBeanName" value="sqlSession"/>-->
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- <!– 注入数据源。使用druid来配置数据源。–>-->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis-spring"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="815924"/>-->
<!-- </bean>-->
<!--加载外部的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>
执行结果:
解决方案:
我们可以使用另外属性来替代:
- sqlSessionTemplateBeanName替代sqlSessionTemplate属性。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<!-- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<!-- <property name="sqlSessionTemplate" ref="sqlSession"/>-->
<!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
<property name="sqlSessionTemplateBeanName" value="sqlSession"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!-- <!– 注入数据源。使用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>-->
<!--加载外部的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>
执行结果:
总之:
写死数据源,你MapperScannerConfigurer中注入sqlSessionFactory属性或者sqlSessionTemplate都行,这两个是选择一个注入就可以了,效果一样。但是,如果是要抽取的数据源,你得使用sqlSessionFactoryBeanName替代sqlSessionFactory,或者使用sqlSessionTemplateBeanName替代sqlSessionTemplate才行。
事务(xml和注解两者都试试)
配置文件版本
事务在spring整合mybatis中也很常用。所以这里也展示一些事务的整合配置。
xml的做法:
配置上下面配置信息。
<!--spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--默认事务超时时间-->
<property name="defaultTimeout" value="30000"/>
<!--数据源-->
<property name="dataSource" ref="dataSource" />
<!--提交失败的话,也进行回滚-->
<property name="rollbackOnCommitFailure" value="true"/>
</bean>
<!--开启声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
然后在对应方法上面添加注解就行了:
@Transactional(rollbackFor = Exception.class)
具体例子:
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
public int updateUserName(User user);
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public class UserServiceImpl implements UserService {
// @Autowired
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateUserName(Integer id,String name1, String name2) {
User user1= new User();
user1.setId(id);
user1.setUsername(name1);
userMapper.updateUserName(user1);
int i=1/0;
User user2= new User();
user2.setId(id);
user2.setUsername(name2);
userMapper.updateUserName(user2);
return 1;
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
public int updateUserName(Integer id,String name1, String name2);
}
package com.yimeng;
import com.yimeng.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean并执行
UserService userService = (UserService) ctx.getBean("userService");
System.out.println("执行前:"+userService.findAll());
try {
userService.updateUserName(1,"梦一","一梦");
} catch (Exception e) {
// e.printStackTrace();
System.out.println("错误了!");
}
System.out.println("执行前:"+userService.findAll());
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yimeng.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!--注册Service的bean-->
<bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">
<!--注入bean-->
<property name="userMapper" ref="userMapper"/>
</bean>
<!--加载外部的properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
<!--注入SqlSessionFactoryBean并配置SqlSessionFactory相关的信息-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源配置。数据源必须在这里指定,不能以configLocation的方式引入。-->
<property name="dataSource" ref="dataSource"/>
<!--通过configLocation属性指定mybatis核心配置文件mybatis-config.xml路径。那些东西,我们可以用这种方式放在一个新的配置文件中去。-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
<property name="transactionFactory">
<!--使用JdbcTransactionFactory进行事务管理-->
<!-- <bean class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>-->
<!--使用SpringManagedTransactionFactory进行事务管理-->
<bean class="org.mybatis.spring.transaction.SpringManagedTransactionFactory"/>
</property>
</bean>
<!--spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--默认事务超时时间-->
<property name="defaultTimeout" value="30"/>
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--提交失败的话,也进行回滚-->
<property name="rollbackOnCommitFailure" value="true"/>
</bean>
<!--开启声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis-spring
jdbc.username=root
jdbc.password=815924
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
<update id="updateUserName">
update user set username=#{username} where id=#{id}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-spring-transaction</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
数据库:
/*
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 */;
执行结果:
这里好像并没有看到mybatis与spring事务整合的相关代码,事实上,这里对开发者屏蔽了。
mybatis的jar包中自身提供了一个TransactionFactory接口和ManagedTransactionFactory、JdbcTransactionFactory。当通过mybatis-spring与spring进行整合后,spring中自带了另外一个TransactionFactory接口的实现SpringManagedTransactionFactory,spring集成mybatis默认使用的就是这个事务管理器。如下图:
SpringManagedTransactionFactory,顾名思义,作用就是讲事务委托给spring进行管理。
上面的内容中,我们多次讲到xml配置mybats,其中多次提到的SqlSessionFactoryBean中,就有一个transactionFactory属性,我们可以使用这个属性控制mybatis使用的事务管理器。比如,我们可以通过这个属性,让mybatis使用JdbcTransactionFactory事务管理器来管理事务(当然哈,在spring中还是建议使用SpringManagedTransactionFactory这个spring提供的事务管理器来进行事务管理)。
很多情况下,我们不指定这个属性。如果没有指定的情况下,默认就是使用SpringManagedTransactionFactory来管理控制事务,相当于是把事务交给spring来管理。
注解版本
package com.yimeng.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@MapperScan(
//等价于MapperScannerConfigurer的basePackage属性。扫描mapper接口的包路径,自动生成实现类。加上mapper包扫描,即basePackages属性,并且指定了markerInterface或者annotationClass,那么只有标记的接口自动生成实现类。但是,如果只写basePackages属性,不指定markerInterface或者annotationClass,那么这个包下的接口都会被自动生成实现类。
basePackages = "com.yimeng.mapper",
// //等价于MapperScannerConfigurer的markerInterface属性。自定义标记要生成实现类的接口。
// markerInterface = YMMapperInterface.class,
// //等价于MapperScannerConfigurer的annotationClass属性。使用mybatis的标记接口。
// annotationClass = Mapper.class,
//等价于MapperScannerConfigurer的sqlSessionFactoryBeanName属性
sqlSessionFactoryRef = "sqlSessionFactory"
)
@EnableTransactionManagement // 启用声明式事务管理
public class DataBaseConfig {
//定义数据源
@Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setUsername("root");
dataSource.setPassword("815924");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring");
dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
return dataSource;
}
//定义SqlSessionFactoryBean
@Autowired
@Bean("sqlSessionFactory")
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setDataSource(dataSource);
ssfb.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
return ssfb;
}
// Spring 事务管理器
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
// 设置数据源
transactionManager.setDataSource(dataSource);
// 设置默认事务超时时间(单位:秒)
transactionManager.setDefaultTimeout(30); // 设置为30秒
// 提交失败时进行回滚
transactionManager.setRollbackOnCommitFailure(true);
return transactionManager;
}
}
package com.yimeng.config;
// 接口名字可以随便定义的,只是作为一个标记的作用
public interface YMMapperInterface {
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
//@Mapper
//public interface UserMapper extends YMMapperInterface {
public interface UserMapper {
public List<User> findAll();
public int updateUserName(User user);
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// @Autowired注解不需要手动写set方法
// public void setUserMapper(UserMapper userMapper) {
// this.userMapper = userMapper;
// }
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateUserName(Integer id, String name1, String name2) {
User user1 = new User();
user1.setId(id);
user1.setUsername(name1);
userMapper.updateUserName(user1);
int i = 1 / 0;
User user2 = new User();
user2.setId(id);
user2.setUsername(name2);
userMapper.updateUserName(user2);
return 1;
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
public int updateUserName(Integer id,String name1, String name2);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <!–注册Service的bean–>-->
<!-- <bean id="userService" class="com.yimeng.service.impl.UserServiceImpl">-->
<!-- <!–注入bean–>-->
<!-- <property name="userMapper" ref="userMapper"/>-->
<!-- </bean>-->
<!-- 扫描包。想要用注解@Service等bean的注解,那么就要使用这个扫描。 -->
<context:component-scan base-package="com.yimeng"/>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
<update id="updateUserName">
update user set username=#{username} where id=#{id}
</update>
</mapper>
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest {
@Resource
private UserService userService;
@Test
public void test(){
System.out.println("执行前:"+userService.findAll());
try {
userService.updateUserName(1,"梦一","一梦");
} catch (Exception e) {
// e.printStackTrace();
System.out.println("错误了!");
}
System.out.println("执行前:"+userService.findAll());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-spring-transaction-anno</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--spring_mybatis桥梁-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version> <!-- 请根据需要确认最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
</project>
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
执行结果:
分析1:@EnableTransactionManagement替代<tx:annotation-driven transaction-manager=“transactionManager”/>
分析2:看图就行。
spring整合mybatis的原理(简单介绍,自己的话)
简单的讲一下spring整合mybatis的原理。具体的可以看本文件夹的另一篇笔记《spring集成mybatis为什么不用写核心类》。
Mybatis的核心对象是SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession。spring集成mybatis其实底层也是使用这三个对象的,和不使用spring一样,都是靠这三个核心对象来完成最终效果的。
上面spring集成mybatis的多种方式中,我就解析“Spring整合Mybatis方式四(非注解MapperScannerConfigurer)”的原理,这个比较好讲。
通过上面的学习,我们知道了,spring集成mybatis的时候,会注册一个id为sqlSessionFactory的bean给spring,一般我们使用的实现类是SqlSessionFactoryBean,所以这里先从SqlSessionFactoryBean开始讲。
-
SqlSessionFactoryBean类在成员变量中就创建了SqlSessionFactoryBuilder对象。这样后面就可以使用SqlSessionFactoryBuilder对象来创建SqlSessionFactory了。所以如果注入的sqlSessionFactory是单例的,那么SqlSessionFactoryBuilder也会是单例的(SqlSessionFactoryBuilder对象最好其实就是创建一次就行了)。
-
SqlSessionFactoryBean实现了InitializingBean接口,并重写了afterPropertiesSet()方法,afterPropertiesSet()方法会在bean的设置到spring容器中的时候被自动被调用。并且在重写的afterPropertiesSet()方法中,完成了SqlSessionFactory对象的创建,以及相关配置文件和映射文件的解析操作。
-
并且这个类也实现了FactoryBean接口,并重写了getObject()方法,也就是说,从spring中获取bean的时候,其实是调用getObject方法返回的结果。这个getObject返回的结果,其实就是SqlSessionFactory对象(上面讲到的这个对象)。
-
所以传给MapperScannerConfigurer的就是SqlSessionFactoryBean的getObject方法返回的SqlSessionFactory对象。
-
接下来我们看MapperScannerConfigurer。MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口。BeanDefinitionRegistryPostProcessor 是BeanFactoryPostProcessor的子类,里面有一个postProcessBeanDefinitionRegistry()方法。实现了这个接口,Spring创建Bean之前会调用这个方法。我们去找到MapperScannerConfigurer类中的postProcessBeanDefinitionRegistry方法,这个方法才是真正被执行的方法。继续看,我们发现他看到调用了scane方法。scane方法调用了doScan方法,我们知道实际执行的时候是看真正创建的类的doScan方法,所以找到了ClassPathMapperScanner的doScan方法。这个doScan方法中看到调用了processBeanDefinitions方法。一个接口是没法创建实例对象的,所以这里创建对象之前将这个接口类型指向了一个具体的MapperFactoryBean类了,这样就可以创建出这个实例了(创建为实例才能使用这个实例创建出SqlSession)。也就是说,能扫描到的所有的Mapper接口,在容器里面都注册成一个MapperFactoryBean了。通过debug,我们可以看到确实是这样的。
这也就正好解释了,为什么MapperScannerConfigurer能替代MapperFactoryBean了。
-
为什么要注册成MapperFactoryBean呢?首先来看看他们的类图结构
从类图中我们可以看到MapperFactoryBean继承了SqlSessionDaoSupport,所以如果所有的mapper接口都被注册为MapperFactoryBean,那么他们都可以拿到SqlSessionTemplate对象了。然后我们还发现MapperFactoryBean实现了 FactoryBean接口,也就意味着,向容器中注入MapperFactoryBean对象的时候,本质上是把getObject方法的返回对象注入到了容器中。
我们看一下这个getObject方法:
发现其实,就是调用getMapper方法得到的代理对象了。我们注入到service层中的mapper对象,其实就是这个
getObject(mapper接口名)
拿到的代理对象。 -
我自己的一个猜测:在注册为MapperFactoryBean的时候,一些属性值已经被绑定上去了。比如说这个this.getSqlSession(),点进去看到是sqlSessionTemplate,但是这个sqlSessionTemplate什么时候被赋值的,我没有注意到,所以,我想,这个一定是在把mapper注册为MapperFactoryBean并实例化后,在某个我没有看到的角落偷偷地把对应的值绑定上去的,并且很有可能是利用xml中配置的sqlSessionFactory去创建出sqlSessionTemplate并且绑定到MapperFactoryBean的属性中去的。
如果看完我上面简单介绍的spring整合mybatis的原理还是不怎么理解,那么可以去看看这三篇写得比较好的文章:https://blog.csdn.net/tianshouzhi/article/details/103922850、https://blog.csdn.net/m0_71777195/article/details/129224916、https://blog.csdn.net/qq_41301079/article/details/102231881
版本五:springboot集成mybatis
例子:
package com.yimeng.config;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer=new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.yimeng.**.mapper");
return mapperScannerConfigurer;
}
}
package com.yimeng.domain;
import lombok.Data;
@Data
public class User {
private int id;
private String username;
private String password;
}
package com.yimeng.mapper;
import com.yimeng.domain.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
package com.yimeng.service.impl;
import com.yimeng.domain.User;
import com.yimeng.mapper.UserMapper;
import com.yimeng.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
}
package com.yimeng.service;
import com.yimeng.domain.User;
import java.util.List;
public interface UserService {
public List<User> findAll();
}
package com.yimeng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisApplication.class, args);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yimeng.mapper.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.yimeng.domain.User" alias="user"/>
</typeAliases>
<!--加载映射文件-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis-spring
username: root
password: 815924
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
package com.yimeng;
import com.yimeng.domain.User;
import com.yimeng.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
public class SpringbootMybatisApplicationTests {
@Resource
private UserService userService;
@Test
void findAll() {
List<User> userList = userService.findAll();
System.out.println(userList);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
</parent>
<groupId>org.example</groupId>
<artifactId>springboot-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
</dependencies>
</project>
sql:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 8.0.30 : Database - mybatis-spring
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis-spring` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `mybatis-spring`;
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`password`) values (1,'张三','123456'),(2,'李四','666666'),(3,'spring','123456'),(4,'spring','123456');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
执行结果:
分析1:
下面这两个bean在springboot集成mybatis中都没有看到声明。
我们只看到了这些配置:
那么springboot是怎么执行mybatis,并且可以成功的呢?
解释一下:因为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。
更具体的分析可以看:https://blog.csdn.net/weixin_45511500/article/details/124571380
扩展:
因为mybatis起步依赖中的bean在发现你自己有注入对应的MapperScannerConfigurer和SqlSessionFactoryBean就不会创建bean放到spring中。所以就是说,你可以完全自己注入这两个bean,而不用起步依赖注入这两个bean。所以我们下面这样做也行:
这里扩展这里的代码就变动了MybatisConfig和application.yaml
所以在这里只贴出这两个代码,其他代码还是和上面的“spring整合mybatis的原理”中的一样。
package com.yimeng.config; import com.alibaba.druid.pool.DruidDataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import javax.sql.DataSource; @Configuration public class MybatisConfig { @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis-spring"); dataSource.setUsername("root"); dataSource.setPassword("815924"); return dataSource; } @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml")); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.yimeng.**.mapper"); return mapperScannerConfigurer; } }
#spring: # datasource: # driver-class-name: com.mysql.cj.jdbc.Driver # url: jdbc:mysql://localhost:3306/mybatis-spring # username: root # password: 815924 # type: com.alibaba.druid.pool.DruidDataSource # #mybatis: # # 加载全局的配置文件 # configLocation: classpath:mybatis/mybatis-config.xml