简介
什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
- MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录
- Mybatis官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html
持久化
** 持久化是将程序数据在持久状态和瞬时状态间转换的机制。**
- 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等
- JDBC就是一种持久化机制。文件IO也是一种持久化机制
- 在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是
为什么需要持久化服务呢?那是由于内存本身的缺陷引起的
- 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的是,人们还无法保证内存永不掉电。
- 内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直呆在内存中,需要持久化来缓存到外存。
第一个程序
Mybatis依赖
<!--mybatis pom依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--mysql 链接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--junit 测试工具-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!--日志传输-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
<!--解决maven文件过滤-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>XML配置(mybatis-config.xml)
<!--config配置-->
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--xml引用-->
<mapper resource="xxxx/xxx.xml"/>
</mappers>
</configuration>代码
package com.mybatis.dao;
import com.mybatis.pojo.User;
import java.util.List;
/**
* @ProjectName: ssm-framework
* @Package: com.mybatis.Service
* @ClassName: UserDto
* @Author: zd
* @Description:
* @Date: 2021/11/2 11:24
* @Version: 1.0
*/
public interface UserMapper {
List<User> selectUser();
}
package com.mybatis.pojo;
/**
* @ProjectName: ssm-framework
* @Package: com.mybatis.pojo
* @ClassName: User
* @Author: zd
* @Description:
* @Date: 2021/11/2 11:17
* @Version: 1.0
*/
public class User {
private int id;
private String name;
private String pwd;
}
/**
* mybayis工具类
*/
package com.mybatis.uils;
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.InputStream;
/**
* @ProjectName: ssm-framework
* @Package: com.mybatis.uils
* @ClassName: MybatisUtils
* @Author: zd
* @Description:
* @Date: 2021/11/2 11:27
* @Version: 1.0
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource ="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
//获取SqlSession链接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
/**
* 测试类
*/
@Test
public void connTest(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
List<User> list=mapper.selectUser();
list.forEach(user -> System.out.println(user));
}<!--接口对应的XML配置-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.dao.UserMapper">
<select id="selectUser" resultType="com.mybatis.pojo.User">
select * from user
</select>
</mapper><mappers>
<!--xml在mybatis-config.xml中配置引用-->
<mapper resource="com/kuang/dao/userMapper.xml"/>
</mappers>CRUD操作及配置解析
namespace
接口xml中的配置参数,namespace属性要指定接口的全限定类名, 与接口的完整包名,必须一致! 。
<mapper namespace="com.mybatis.dao.UserMapper">select
- select语句有很多属性可以详细配置每一条SQL语句
- SQL语句返回值类型【完整的类名或者别名】
- 传入SQL语句的参数类型 【万能的Map,可以多尝试使用】
- 命名空间中唯一的标识符
- 接口中的方法名与映射文件中的SQL语句ID 一一对应
- id 对应的namespace中的方法名, parameterType 参数类型, resultType sql语句执行的返回值。
//接口
public interface UserMapper {
//返回集合
List<User> selectUser();
//返回对象
User selById(int id);
//多条件查询
User selByConditions(@Param("name") String name,@Param("pwd") String pwd);
//map集合查询
User selByMap(Map<String, String> map);
}
//测试类
public class DemoTest {
@Test
public void connTest(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
List<User> list=mapper.selectUser();
list.forEach(user -> System.out.println(user));
}
@Test
public void connTest1(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user=mapper.selById(1);
System.out.println(user);
}
@Test
public void connTest2(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user=mapper.selByConditions("测试","123456");
System.out.println(user);
}
@Test
public void connTest3(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
Map<String, String> map = new HashMap<>();
map.put("pwd","123456");
map.put("name","测试");
User user=mapper.selByMap(map);
System.out.println(user);
}
}<?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.mybatis.dao.UserMapper">
<resultMap id="BaseResultMap" type="com.mybatis.pojo.User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="pwd" jdbcType="VARCHAR" property="pwd"/>
</resultMap>
<sql id="Base_Column_List">
id, name, pwd
</sql>
<select id="selectUser" resultType="com.mybatis.pojo.User">
select * from user
</select>
<select id="selById" resultType="com.mybatis.pojo.User">
select * from user where id = #{id}
</select>
<select id="selByConditions" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"></include>
from user where name = #{name,jdbcType=VARCHAR} AND pwd = #{pwd,jdbcType=VARCHAR}
</select>
<select id="selByMap" parameterType="map" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"></include>
from user where name = #{name,jdbcType=VARCHAR} AND pwd = #{pwd,jdbcType=VARCHAR}
</select>
</mapper>多条件查询需要在接口的参数上添加@Param(“xxx”)参数;
insert
使用新增,修改,删除时,必须使用session.commit()提交事务,否则数据库不会插入数据。
/**
* insert方法
*/
int addUser(User user);
@Test
public void connTest4(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user = new User(4,"新增","Aa123123");
int i=mapper.addUser(user);
System.out.println(i);
//提交事务,必须提交否则数据库不会插入数据
session.commit();
session.close();
}<!--新增-->
<insert id="addUser" parameterType="com.mybatis.pojo.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>update
/**
* update方法
*/
int updateUser(User user);
@Test
public void connTest5(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user = new User(4,"修改","Aa1111");
int i=mapper.updateUser(user);
System.out.println(i);
//提交事务,必须提交否则数据库不会插入数据
session.commit();
session.close();
}<!--修改-->
<update id="updateUser" parameterType="com.mybatis.pojo.User">
update user set name = #{name},pwd = #{pwd} where id = #{id}
</update>delete
/**
* delete删除
*/
int deleteUser(User user);
@Test
public void connTest6(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user = new User(4,"修改","Aa1111");
int i=mapper.deleteUser(user);
System.out.println(i);
//提交事务,必须提交否则数据库不会插入数据
session.commit();
session.close();
}<!--删除-->
<delete id="deleteUser" parameterType="com.mybatis.pojo.User">
delete from user where id = #{id}
</delete>Map传参的sql使用
使用map传参可以对sql传入多个参数,切不按照表中名称或实体类中名称进行引用,若不使用map传多个参数需要使用@Param注解修饰。
@Test
public void connTest3(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
Map<String, String> map = new HashMap<>();
map.put("pwd","123456");
map.put("name","测试");
User user=mapper.selByMap(map);
System.out.println(user);
session.close();
}<select id="selByMap" parameterType="map" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"/>
from ssm_framework.user where name = #{name,jdbcType=VARCHAR} AND pwd = #{pwd,jdbcType=VARCHAR}
</select>模糊搜索
第1种:在Java代码中添加sql通配符
String str = "%测试%";
<select id="selByString" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"/>
from user where name like #{str}
</select>第2种:在sql语句中拼接通配符,会引起sql注入**(不建议使用)**
<select id="selByLike" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"/>
from user where name like "%"#{str}"%"
</select>第3种:$符替换
<select id="selByLike" resultType="com.mybatis.pojo.User">
select
<include refid="Base_Column_List"/>
from user where name like '%${str}%'
</select>小结:
- 所有的增删改操作都需要提交事务!
- 接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!
- 有时候根据业务的需求,可以考虑使用map传递参数!
- 为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上!
核心配置文件(mybatis-config.xml)
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
environments元素
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>- environments元素用来配置多个数据库环境,需要用default属性默认一个运行环境;
- environment子元素
- dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 数据源是必须配置的,且包含三种内建数据源类型:
type="[UNPOOLED|POOLED|JNDI]")
UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
pooled:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。- 数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等....
- 子元素节点:transactionManager - [ 事务管理器 ] , 这两种事务管理器类型都不需要设置任何属性。
<!-- 语法 -->
<transactionManager type="[ JDBC | MANAGED ]"/>properties元素
可以在外部进行配置,并进行动态替换,可以在java属性文件中配置属性,也可在properties元素中配置;
properties配置中,如果properties文件与property属性存在相同名称的配置,则优先使用properties文件,最后使用property属性的配置。
<!--引入外部配置文件-->
<properties resource="db.properties">
<property name="root" value="123"/>
<property name="password" value="123456"/>
</properties>
<!--环境配置-->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<!--或在属性中添加-->
<properties resource="db.properties">
<property name="root" value="root"/>
<property name="password" value="123456"/>
</properties>settings元素
log日志
设置mybatis的行为,其中logImpl为设置mybatis日志;

Log4j输出:
<!--引入包-->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
#不显示sql结果集
log4j.logger.org.mybatis=DEBUG
#显示sql结果集
log4j.logger.org.mybatis=TRACE
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG配置log4j为日志的实现
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>log4j在类中的使用
- 在要使用log4j的类中引入;
- 日志对象定义,参数为当前类的class文件
- 日志级别debug,info,error等;
static Logger logger = Logger.getLogger(DemoTest.class);
logger.info("info级别");
logger.debug("debug级别");
logger.error("error级别");typeAliases元素(类型别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写 。
- 在config中配置类名别名
<typeAliases>
<typeAlias type="com.mybatis.pojo.User" alias="User"></typeAlias>
</typeAliases>
<!--加别名后结果集可直接改为别名-->
<!--<select id="selByLike" resultType="com.mybatis.pojo.User">-->
<select id="selByLike" resultType="User">
select
<include refid="Base_Column_List"/>
from user where name like "%"#{str}"%"
</select>- 扫描包加别名
当实体类过多时,可以使用package属性进行起别名,默认会将该包名下的所有类名首字母大写改为小写。
例:User→user;
<typeAliases>
<package name="com.mybatis.pojo"></package>
</typeAliases>不可DIY别名,如果要改可使用注解添加在类名上,注解别名优先级高于xml配置别名;
@Alias("user")
public class User {}- 常用的数据类型,在命名上不区分大小写,命名规则如下:
| 别名 | 映射类型 | 别名 | 映射类型 |
|---|---|---|---|
| _byte | byte | double | Double |
| _long | long | float | Float |
| _short | short | boolean | Boolean |
| _int | int | date | Date |
| _integer | int | decimal | BigDecimal |
| _double | double | bigdecimal | BigDecimal |
| _float | float | object | Object |
| _boolean | boolean | map | Map |
| string | String | hashmap | HashMap |
| byte | Byte | list | List |
| long | Long | arraylist | ArrayList |
| short | Short | collection | Collection |
| int | Integer | iterator | Iterator |
| integer | Integer |
mappers元素
映射器 : 定义映射SQL语句文件
可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///D:/mywork/ssm-framework/mybatis-framework/src/main/resources/mapper/UserMapper.xml"/>
</mappers>
<!--
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!--
将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>生命周期和作用域

- SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
- SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
- 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
- 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
- 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。
- 所以 SqlSession 的最佳的作用域是请求或方法作用域。

ResultMap及分页
字段取别名
当实体类中的字段名与数据库中的字段名不一致时,查询结果会返回null;
@Alias("us")
public class User {
private int id;
private String name;
private String passward;
}<select id="selByLike" resultType="us">
select * from user where name like "%"#{str}"%"
</select>返会结果为:
User{id=1, name='测试', passward='null'}User{id=2, name='张测', passward='null'}解决方案:
<!--为列名指定别名 , 别名和java实体类的属性名一致-->
<sql id="Base_Column_List">
id, name, pwd as passward
</sql>
<select id="selByLike" resultType="us">
select <include refid="Base_Column_List"/> from user where name like "%"#{str}"%"
</select>
<!--使用结果集映射->ResultMap 【推荐】-->
<resultMap id="BaseResultMap" type="com.mybatis.pojo.User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="pwd" jdbcType="VARCHAR" property="passward"/>
</resultMap>
<select id="selByLike" resultMap="BaseResultMap">
select <include refid="Base_Column_List"/> from user where name like "%"#{str}"%"
</select>ResultMap
- 自动映射
使用POJO类或数据类型的映射,不需要手动配置,直接使用resultType属性配置即可;
- 手动映射
当数据库中字段名和实体类中字段名不一致时,就需要手动映射将数据库字段与实体类字段一一映射对应,返回类型使用ResultMap配置引用。
<resultMap id="BaseResultMap" type="com.mybatis.pojo.User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="pwd" jdbcType="VARCHAR" property="pwd"/>
</resultMap>
<select id="selByLike" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from user where name like "%"#{str}"%"
</select>分页的几种方式
- 使用Limit实现分页
#语法
SELECT * FROM table LIMIT stratIndex,pageSize
#索引查询5-15行
SELECT * FROM table LIMIT 5,10;
#查询第n行之前的数据,如果只给定一个参数,它表示返回最大的记录行数目
SELECT * FROM table LIMIT 5;在sql中,limit分页起始位置参数设置:
起始位置 = (当前页面 - 1 ) * 页面大小
<select id="selByPage" resultMap="BaseResultMap">
select * from mybatis.user limit #{startPage,javaType=INTEGER},#{pageSize,javaType=INTEGER}
</select> @Test
public void connTest9(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
int startPage = 1;
int pageSize = 20;
Map<String, Integer> map = new HashMap<>();
map.put("startPage",(startPage-1)*pageSize);
map.put("pageSize",pageSize);
List<User> list=mapper.selByPage(map);
list.forEach(user -> System.out.print(user.toString()));
session.close();
}
/**
* 分页查询
*/
List<User> selByPage(Map<String, Integer> map);- RowBounds分页
//选择全部用户RowBounds实现分页
List<User> getUserByRowBounds();
@Test
public void testUserByRowBounds() {
SqlSession session = MybatisUtils.getSession();
int currentPage = 2; //第几页
int pageSize = 2; //每页显示几个
RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
//通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user: users){
System.out.println(user);
}
session.close();
}<select id="getUserByRowBounds" resultType="user">
select * from user
</select>- PageHelper插件
官方文档:https://pagehelper.github.io/
<!--pom引入-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>Mybatis执行流程

使用注解开发
注解开发
- mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。最强大的 MyBatis 映射并不能用注解来构建。
- sql类型主要成分:
- @select()
- @update()
- @insert()
- @delete()
注意:使用注解开发就不用mapper.xml映射文件
/**
* 注解查询
*/
@Select("select * from mybatis.user")
List<User> getAllUser();
@Test
public void connTest10(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
List<User> list=mapper.getAllUser();
list.forEach(user -> System.out.println(user.toString()));
session.close();
}@Param注解
@Param注解用于给方法参数起名:
- 在方法只接收一个基本类型参数时,可以不使用@Param;
- 在方法接收多个参数时,一定要使用@Param注解给参数起名;
- 如果参数是JavaBean,不能使用@Param;
User selByConditions(@Param("name") String name,@Param("pwd") String pwd);${}符和#{}符的区别
- #{}的作用是替换预编译语句中的占位符?(推荐使用)
INSERT INTO user (name) VALUES (#{name});
INSERT INTO user (name) VALUES (?);- ${}的作用是直接进行字符串替换
INSERT INTO user (name) VALUES ('${name}');
INSERT INTO user (name) VALUES ('kuangshen');Lombok
引入包且在编译器下载插件
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>@Getter and @Setter
代替getset方法
@ToString
构建toSring方法
@EqualsAndHashCode
构建equals和hashCode方法
@AllArgsConstructor,@NoArgsConstructor
构建所有参数构造方法及无参构造方法
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
构建logFactory对象,日志输出使用。
@Data
构建get、set、无参构造方法,重写hashcode、equals方法。
@Builder
@Value
构建get方法
@Accessors(chain=true)
结合@Data注解使用可生成set链式编程,即set方法返回本对象;
复杂sql实现
create table teacher(
id int(10) not null primary key auto_increment comment '主键id',
name varchar(20) default null comment 'name'
)engine =INNODB DEFAULT CHARSET =utf8;
insert into teacher(`name`) values ('张三');
create table student(
id int(10) not null primary key auto_increment comment '主键id',
name varchar(20) default null comment '姓名',
tid int(10) default null comment '老师id',
key `fktid` (tid),
constraint `fktid` foreign key (`tid`) references `teacher` (id)
)engine =INNODB DEFAULT CHARSET =utf8;
insert into `student` (name, tid) VALUES ('小明',1);
insert into `student` (name, tid) VALUES ('小红',1);
insert into `student` (name, tid) VALUES ('小华',1);
insert into `student` (name, tid) VALUES ('小王',1);一对多
当返回的一条数据中存在另一个类的数据,且为集合时,由于实体类字段和数据库字段不匹配需要使用resultMap映射,在映射中使用collection标签进行关联。collection中要将javaType替换为ofType。
按照结果嵌套处理
<mapper namespace="com.mybatis.dao.TeacherMapper">
<select id="getTeacherAndStudents" resultMap="TeacherAndStudents">
select t.id tid, t.name tname, s.id sid, s.name sname
from student as s,
teacher as t
where t.id = s.tid
and t.id = #{tid};
</select>
<!--按结果嵌套查询-->
<resultMap id="TeacherAndStudents" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--实体类中参数为集合时,使用collection映射,使用ofType代替javaType-->
<collection property="list" ofType="com.mybatis.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="tname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>按照查询嵌套处理
<mapper namespace="com.mybatis.dao.TeacherMapper">
<select id="getTeacherAndStudents2" resultMap="TeacherAndStudents2">
select * from teacher where id = #{id};
</select>
<select id="getStudents" resultType="Student">
select * from student where id = #{tid};
</select>
<!--按结果嵌套查询-->
<resultMap id="TeacherAndStudents2" type="Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--实体类中参数为集合时,使用collection映射,使用ofType代替javaType-->
<collection property="list" javaType="arraylist" ofType="Student" column="id" select="getStudents">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper> 多对一
查询所有学生及老师信息
select s.name,t.name from student as s ,teacher as t where s.tid = t.id;按照查询嵌套处理
@Data
public class Student {
private String id;
private String name;
//学生关联老师
private Teacher teacher;
}
@Data
public class Teacher {
private String id;
private String name;
}<resultMap id="StudentAndTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂类型的返回类型,返回对象使用:association 返回集合使用:collection -->
<association property="teacher" javaType="Teacher" column="tid" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{tid};
</select>
<select id="getAllStudentAndTeacher" resultMap="StudentAndTeacher">
select * from student;
</select>按照结果嵌套处理
<resultMap id="StudentAndTeacher2" type="Student">
<result property="id" column="id"/>
<result property="name" column="sname"/>
<!--复杂类型的返回类型,返回对象使用:association 返回集合使用:collection -->
<association property="teacher" javaType="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="getAllStudentAndTeacher2" resultMap="StudentAndTeacher2">
select s.id as id,s.name as sname,t.id as tid,t.name as tname from student as s ,teacher as t where s.tid = t.id;
</select>javaType:用来指定类属性中的对象;
ofType:用来指定映射到集合中的pojo类型,泛型中的约束类型.
动态sql
根据不同的参数生成不同的sql,如多条件查询,不为null的属性进行查询。
if语句
如果使用多个条件查询时,当第一个参数为空时,第二个参数为where and xxx = #{xxx},所以使用where 1=1不合适,建议使用
<select id="getTeacherAndStudents2" resultMap="TeacherAndStudents2">
select id,name from ssm_framework.teacher where 1=1
<if test ='id != null'>
id = #{id}
</if>
</select>trim(where,set)语句
where标签在使用时,如果后缀条件满足时,会将条件语句前的and或or去掉,拼接sql。
set标签与where同理,去掉多余的逗号。
choose(when,otherwise)语句
<select id="getTeacherAndStudents2" resultMap="TeacherAndStudents2">
select id,name,address from ssm_framework.teacher where 1=1
<choose>
<when test = 'address == '西安''>
and name = #{name}
</when>
<when test = 'address == '北京''>
and id = #{id}
</when>
<otherwise>
and id = #{id} and name = #{name}
</otherwise>
</choose>
</select>foreach语句
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>sql片段
多个sql存在公共语句时,会抽取出来当做sql片段,如:查询字段或查询条件修改条件。
<sql id="Base_map">
id,name
</sql>
<select id="getTeacherAndStudents2" resultMap="TeacherAndStudents2">
select <include refid="Base_map"/> from ssm_framework.teacher where id = #{id};
</select>缓存
一级缓存
本地缓存,作用域为session级别,即一次连接内相同的查询会在缓存中取;
@Test
public void connTest2(){
SqlSession session=MybatisUtils.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
User user=mapper.selByConditions("测试","123456");
User user2=mapper.selByConditions("测试","123456");
System.out.println(user);
System.out.println(user2);
System.out.println(user == user2);
session.close();
}
//输出
[com.mybatis.dao.UserMapper.selByConditions]-==> Preparing: select id, name, pwd from ssm_framework.user where name = ? AND pwd = ?
[com.mybatis.dao.UserMapper.selByConditions]-==> Parameters: 测试(String), 123456(String)
[com.mybatis.dao.UserMapper.selByConditions]-<== Total: 1
User{id=2, name='测试', pwd='123456'}
User{id=2, name='测试', pwd='123456'}
true二级缓存
在mybatis-config.xml中,开启缓存;
<!--开启去全局二级缓存-->
<setting name="cacheEnabled" value="true"/>mapper.xml开启二级缓存
<!--在当前mapper中开缓存-->
<cache/>针对查询语句进行开启缓存
<select id="selById" parameterType="int" resultType="com.mybatis.pojo.User" useCache="true">
select * from ssm_framework.user where id = #{id}
</select>二级缓存生命周期是第一个session结束连接后,会将一级缓存的数据传递给二级缓存。二级缓存需要对实体类进行序列化。