MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
总结起来就是:不要编写 JDBC 代码了,但是要自己编写 sql。使用 Mybatis 可以使得编写 Java 业务代码和编写映射文件中的 sql 语句独立解耦,Mybatis 会将接口映射到对应映射文件,实体类对象映射到对应的数据库表中的记录。
创建数据库表和实体类
表:tb_user
CREATE TABLE IF NOT EXISTS tb_user (
id INT (5) NOT NULL PRIMARY KEY,
NAME VARCHAR (45),
age INT (3),sql
sex CHAR
)
实体类:User
public class User {
private int id;
private String name;
private int age;
private String sex;
}
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
dependencies>
核心配置文件存放的位置是 src/main/resources 目录下。
核心配置文件 mybatis-config.xml 用于配置 mybatis 相关的信息,主要用于配置连接数据库的环境以及MyBatis的全局配置信息。
核心配置文件中的标签按照需要配置,但之间有相对配置顺序,若配置时将它们之间的顺序颠倒,会提示报错: properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorF actory?,plugins?,environments?,databaseIdProvider?,mappers?
入门使用中一定要配置 environments 标签以操作数据库,配置 mappers 标签告诉 mybatis 去哪找映射文件,其他设置可以根据需要进行配置。
DOCTYPE configuration
PUBLIC "-//MyBatis.org//DTD Config 3.0//EN"
"http://MyBatis.org/dtd/MyBatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<typeAlias type="com.qgl.mybatis.pojo.User">typeAlias>
<typeAlias type="com.qgl.mybatis.pojo.User" alias="abcd">
<package name="com.qgl.mybatis.pojo"/>
typeAliases>
<environments default="mysql_test">
<environment id="mysql_test">
<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="mappers/UserMapper.xml"/>s
<package name="com.qgl.mybatis.mappers"/>
mappers>
configuration>
mapper 仅仅是一个接口,不需要提供实现类,会通过 MyBatis 的强大的映射功能,将接口中的方法映射到对应映射文件中的 sql 语句,然后去操作数据库。
public interface UserMapper {
User selectById(int id);
}
mapper 映射文件和 mapper 接口是一一对应的,在映射文件中编写 sql。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qgl.mybatis.mappers.UserMapper">
<select id="selectById" parameterType="int" resultType="com.qgl.mybatis.pojo.User">
select * from tb_user where id = #{id}
select>
mapper>
import org.apache.ibatis.io.Resources;
@Test
public void selectByIdTest() throws IOException {
String resource = "mybatis-config.xml";
//读取 MyBatis 核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建 SqlSessionFactory 工程
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取 SqlSession 会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过代理模式创建 UserMapper 接口的代理实现类对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用 UserMapper 接口中的方法,就可以根据 UserMapper 的全限定类名匹配映射文件,通过调用的方法名匹配映射文件中的 SQL 标签,并执行标签中的 SQL 语句。
User user = mapper.selectById(1);
System.out.println(user);
}
映射关联关系:
接口名和映射文件名可以不一样,因为他们之间通过
实体类名和数据库表名可以不一样,因为他们之间通过 sql 标签中的 resultType 属性指定哪个实体类来接收。但建议实体类名和表名一致。
resultType:自动映射,用于属性名和表中字段名一致的情况。resultType 属性值指定的实体类的属性名是要和表中字段名一致,否则对应不上,不会报错,但该属性不会接收对应数据。实体类中的属性个数不一定要和表中字段个数一致,不会报错,只是查询到的结果可能不能完全对应接收。
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况。若实体类的属性名和表中字段名不一致,可以通过自定义映射关系来建立之间的联系。
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
创建一个名为 log4j.properties 的配置文件进行配置
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.com.qgl.mybatis.mappers.UserMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
也可以创建 log4j.xml 文件进行配置
DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
%m (%F:%L) \n" />
layout>
appender>
<logger name="com.qgl.mybatis.mappers.UserMapper">
<level value="trace" />
logger>
<logger name="java.sql">
<level value="debug" />
logger>
<logger name="org.apache.ibatis">
<level value="info" />
logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
root>
log4j:configuration>
MyBatis 获取参数值的两种方式:${} 和 #{}
${} 的本质就是字符串拼接,#{} 的本质就是占位符赋值。
${} 使用字符串拼接的方式拼接 sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是 #{} 使用占位符赋值的方式拼接 sql,此时为字符串类型或日期类型的字段进行赋值时,它会自动添加单引号。
例:使用 ${} 拼接,即字符串拼接。存在 sql 注入的问题。
<select id="selectById" parameterType="int" resultType="com.qgl.mybatis.pojo.User">
select * from tb_user where id = ${id}
select>
输出的 sql 语句为:
DEBUG 12-04 10:52:32,230 ==> Preparing: select * from tb_user where id = 1 (BaseJdbcLogger.java:137)
DEBUG 12-04 10:52:32,254 ==> Parameters: (BaseJdbcLogger.java:137)
例:使用 #{} 拼接,即占位符赋值。
<select id="selectById" parameterType="int" resultType="com.qgl.mybatis.pojo.User">
select * from tb_user where id = ${id}
select>
输出的 sql 语句为:
DEBUG 12-04 10:56:28,863 ==> Preparing: select * from tb_user where id = ? (BaseJdbcLogger.java:137)
DEBUG 12-04 10:56:28,885 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137)
如果拼接的是字符串或日期类型的字段。${} 需要加单引号。
<select id="selectByName" parameterType="String" resultType="com.qgl.mybatis.pojo.User">
select * from tb_user where name = '${name}'
select>
输出的 sql 语句为:
DEBUG 12-04 11:00:29,355 ==> Preparing: select * from tb_user where name = '张三' (BaseJdbcLogger.java:137)
DEBUG 12-04 11:00:29,381 ==> Parameters: (BaseJdbcLogger.java:137)
${} 和 #{} 中的属性名和接口传参中的变量名一致,若两者不一致,使用 @Param 注解标识参数来作为属性名。
User selectById(@Param("name") String other);
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.2.0version>
dependency>
在 Mybatis 核心配置文件中注册分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
plugins>
在查询功能之前使用 PageHelper.startPage(int pageNum, int pageSize) 开启分页功能。
在查询获取 list 集合之后,可以使用 PageInfo pageInfo = new PageInfo<>(List list, int navigatePages) 获取分页相关数据。
例:
public void selectByIdTest() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//开启分页功能
PageHelper.startPage(1,2);
List<User> users = mapper.selectList();
for (User user : users) {
System.out.println(user);
}
//获取分页相关的结果
PageInfo<User> pageInfo = new PageInfo<>(users);
System.out.println(pageInfo);
}
输出:
DEBUG 12-04 11:22:26,794 Cache Hit Ratio [SQL_CACHE]: 0.0 (LoggingCache.java:60)
DEBUG 12-04 11:22:26,835 ==> Preparing: SELECT count(0) FROM tb_user (BaseJdbcLogger.java:137)
DEBUG 12-04 11:22:26,860 ==> Parameters: (BaseJdbcLogger.java:137)
TRACE 12-04 11:22:26,875 <== Columns: count(0) (BaseJdbcLogger.java:143)
TRACE 12-04 11:22:26,875 <== Row: 4 (BaseJdbcLogger.java:143)
DEBUG 12-04 11:22:26,877 <== Total: 1 (BaseJdbcLogger.java:137)
DEBUG 12-04 11:22:26,879 ==> Preparing: select * from tb_user LIMIT ? (BaseJdbcLogger.java:137)
DEBUG 12-04 11:22:26,880 ==> Parameters: 2(Integer) (BaseJdbcLogger.java:137)
TRACE 12-04 11:22:26,881 <== Columns: id, name, age, sex (BaseJdbcLogger.java:143)
TRACE 12-04 11:22:26,881 <== Row: 1, 张三, 23, 男 (BaseJdbcLogger.java:143)
TRACE 12-04 11:22:26,882 <== Row: 3, 张三, 24, 男 (BaseJdbcLogger.java:143)
DEBUG 12-04 11:22:26,883 <== Total: 2 (BaseJdbcLogger.java:137)
User(id=1, name=张三, age=23, sex=男, idCard=null)
User(id=3, name=张三, age=24, sex=男, idCard=null)
PageInfo{pageNum=1, pageSize=2, size=2, startRow=1, endRow=2, total=4, pages=2, list=Page{count=true, pageNum=1, pageSize=2, startRow=0, endRow=2, total=4, pages=2, reasonable=false, pageSizeZero=false}[User(id=1, name=张三, age=23, sex=男, idCard=null), User(id=3, name=张三, age=24, sex=男, idCard=null)], prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=8, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}
Process finished with exit code 0
分页相关数据:
MyBatis 的强大在于高级映射功能,但需要自己编写接口、实体类和 sql 语句。如果表太多的话,有大量的重复工作,麻烦。所以 MyBatis 官方提供了一个逆向工程,可以针对单表自动生成 MyBatis 执行所需要的代码(包括mapper.xml,mapper.java,pojo)。
正向工程:先创建 Java 实体类,由框架负责根据实体类生成数据库表。Hibernate 是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成代码( Java实体类、Mapper接口、Mapper映射文件)。
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-maven-pluginartifactId>
<version>1.3.0version>
<dependencies>
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.3.2version>
<configuration>
<verbose>trueverbose>
<overwrite>trueoverwrite>
<configurationFile>etc/generatorConfig.xmlconfigurationFile>
configuration>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
dependencies>
plugin>
plugins>
build>
同上。
generatorConfig.xml
DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="123456">
jdbcConnection>
<javaModelGenerator targetPackage="com.qgl.mybatis.pojo" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="com.qgl.mybatis.mappers" targetProject="src/main/resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.qgl.mybatis.mappers" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
<table tableName="tb_user" domainObjectName="User">table>
context>
generatorConfiguration>

<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
同上。
generatorConfig.xml
DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="123456">
jdbcConnection>
<javaModelGenerator targetPackage="com.qgl.mybatis.pojo" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="com.qgl.mybatis.mappers" targetProject="src/main/resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.qgl.mybatis.mappers" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
<table tableName="tb_user" domainObjectName="User">table>
context>
generatorConfiguration>
@Test
public void testMbg() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("src/main/resources/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>3.0.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.12version>
dependency>
#数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
#整合mybatis
#映射文件位置配置
mybatis.mapper-locations=classpath:com/qgl/mybatis/mappers/*.xml
#给pojo实体类起别名
mybatis.type-aliases-package=com.qgl.mybatis.pojo
@MapperScan("com.qgl.mybatis.pojo")