MyBatis
学习本模块可见手册 MyBatis参考文档
下载第三方 jar 包可以参考 下载资源
1、框架概述
1.1、三层架构
MVC :web 开发中,使用 MVC 架构模式。m:数据,v:视图,c:控制器
c 控制器:接收请求,调用 servlet 对象,显示请求的处理结果,当前使用 servlet 作为控制器
v 视图:现在使用 jsp,html ,css,js 。显示请求的处理结果,把 m 中的数据显示出来
m 数据,来自数据库 MySQL、来自文件、来自网络
MVC 作用:
- 实现解耦合
- 让 mvc 各司其职
- 使得系统扩展更好,更容易维护
三层架构:
- 界面层(视图层):接收用户请求,调用 Servlet ,显示请求的处理结果的,包含了 jsp、html、servlet 等对象
- 业务逻辑层:处理业务逻辑,使用算法处理数据的,把数据返回给界面层,对应的是 service 包,和包中的类
- 持久层(数据库访问层):访问数据库,或者读取文件、访问网络、获取数据。对应的是 dao 包和包中的类
三层架构请求的处理流程:
用户发起请求 ------> 界面层 ------> 业务逻辑层 ------> 持久层 ------> 数据库(mysql)
为什么使用三层架构?
- 结构清晰,耦合度低,各层分工明确
- 可维护性高,可扩展性高
- 有利于标准化
- 开发人员可以只关注整个结构中的其中某一层的功能实现
- 有利于各层逻辑的复用
三层架构模式和框架,每一层对应着一个框架:
- 界面层 ------> SpringMVC 框架
- 业务层 ------> Spring 框架
- 持久层 ------> MyBatis 框架
1.2、框架
什么是框架?
- 框架是一个半成品,已经对基础的代码进行了封装并提供相应的 API ,开发者在使用框架时直接调用封装好的 API 可以省去很多代码编写,从而提高工作效率和开发速度
- 框架看做是模板
- 框架是可以升级、改造的,框架是安全的
- 框架对某一个方面有用,不是全能的
- 开发工程师建立在框架的基础之上完成开发部分功能 加 框架自身完成部分功能组成一个完整的产品
框架解决的问题:
- 框架能实现技术的整合
- 提高开发的效率,降低难度
JDBC 访问数据库的优缺点:
- 优点:
- 直观,好理解
- 缺点:
- 创建很多对象 Connection,Statement,ResultSet
- 注册驱动
- 执行SQL语句
- 把 ResultSet 转为 Student 对象、List集合
- 关闭资源
- sql 语句和业务逻辑代码混合在一起
1.3、MyBatis框架概述
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集,MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口、 Java的entity对象 作为数据库中的记录
Mybatis的功能架构分为三层:
- API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收 到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是 共用的东西,将他们抽取出来作为最基础的组件,为上层的数据处理层提供最基础的支撑
Mybatis 能做什么:
- 注册驱动
- 创建 jdbc 中使用的 Connection,Statement,ResultSet
- 执行 SQL 语句,得到 ResultSet
- 处理 ResultSet ,把记录集中的数据转为 java对象,同时将 java对象封装进 List 集合
- 关闭资源
- 实现 SQL 语句和 java 代码的解耦合
2、 MyBatis框架入门
2.1、入门示例
2.1.1、实现步骤:
-
创建数据库表 student(id, name, email, age),新建 maven 项目
-
修改 pom.xml 文件
mybatis 依赖、mysql 驱动、Junit
-
创建实体类 Student ,属性名与数据库字段名保持一致
-
创建 Dao 接口,定义操作数据库的方法
-
创建 mybatis-mapper.xml 文件,编写 SQL 语句
mapper文件:和 dao 接口在同一包,一个表对应一个 mapper 文件
-
创建 mybatis-config.xml 主配置文件,放在 resources 目录下,仅有一个
定义创建连接实例的数据源对象(DataSource)
指定 mapper 文件位置
-
测试
2.1.2、pom.xml
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
2.1.3、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">
<!--
1、约束文件:http://mybatis.org/dtd/mybatis-3-mapper.dtd
作用:定义和限制的当前文件中可以使用的标签和属性,以及标签出现的顺序
2、根标签: mapper
3、命名空间:namespace ,必须有值,不能为空,唯一值
推荐使用 Dao 接口的全限定名称
作用:参与识别 SQL 语句
4、在 mapper根标签里面使用 insert,update,delete,select标签写SQL
-->
<mapper namespace="com.dao.StudentDao">
<!-- 使用 insert,update,delete,select标签写SQL -->
<!--根据 id 查询学生信息
<select>:表示查询操作,里面是 select 语句
id 属性:要执行的 sql 语句的唯一标识,是一个自定义字符串
推荐使用 dao 接口中的方法名称
resultType 属性:告诉 mybatis,执行 sql 语句,把数据赋值给哪个类型的 java 对象
resultType 的值现在使用的是 java 对象的全限定名称
-->
<select id="selectStudentById" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
</mapper>
2.1.4、mybatis主配置文件
<?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="mydb">
<environment id="mydb">
<transactionManager type="JDBC"/>
<!-- 配置数据源:创建 Connection 对象 -->
<dataSource type="POOLED">
<!--driver 驱动信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/book?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
<!--
指定其他 mapper 文件的位置,目的是找到其他文件的 SQL 语句
-->
<mappers>
<!--
使用 mapper标签的 resource 属性指定其他 mapper 文件的路径,这个路径是从 target/classes 路径开始的
使用注意:
1、resource属性值,mapper文件的路径是使用 / 分割路径
2、一个 mapper标签指定一个 mapper 文件
-->
<mapper resource="com/dao/StudentDao.xml"/>
</mappers>
</configuration>
2.1.4、日志功能
在 主配置文件 中添加 setting 标签
<configuration>
<!--设置sql日志 打印在控制台-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
2.1.5、创建核心对象 SqlSession 测试
//测试 MyBatis 执行 SQL 语句
@Test
public void test1() throws IOException {
// 1、定义mybatis主配置文件的位置,从target/calsses路径开始的相对路径
String config = "mybatis.xml";
// 2、读取主配置文件,使用mybatis框架中的Resources类
InputStream inputStream = Resources.getResourceAsStream(config);
// 3、使用SqlSessionFactoryBuilder类,创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 4、获取 SqlSession 对象
SqlSession sqlSession = factory.openSession();
// 5、指定要执行的 sql 语句的 id
// sql的id = namespace + "." + select|update|delete|insert标签的 id 属性值
String sqlId = "com.dao.StudentDao.selectStudentById";
// 6、通过 SqlSession 的方法,执行 sql 语句
Student student = sqlSession.selectOne(sqlId,3);
System.out.println("使用mybatis查询某个学生" + student);
// 7、关闭 SqlSession 对象
sqlSession.close();
}
2.2、手动提交事务
-
自动提交事务:
当你的 SQL 语句执行完毕之后,提交事务,数据库更新操作之后保存数据
-
手动提交事务:
在你需要提交事务的位置,执行方法,提交事务或回滚事务
-
MyBatis 是手动提交事务,在执行 insert、update、delete 的时候需要执行
sqlSession.commit();
提交事务
2.3、MyBatis重要对象
-
Resources
:MyBatis 框架中的对象,用于读取主配置信息InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
-
SqlSessionFactoryBuilder
:负责创建 SqlSessionFactory 对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
-
SqlSessionFactory
:接口,负责创建 SqlSession 对象,实现类 DefaultSqlSessionFactory是重量级对象,创建此对象需要更多资源和时间,所以在项目中有一个就够了
SqlSessionFactory 接口中的方法: openSession() 获取一个默认的 SqlSession 对象,默认是手动提交事务 openSession(true) 表示创建一个自动提交事务的 SqlSession 对象
-
SqlSession
:接口,提供了大量执行 SQL 语句的方法,实现类 DefaultSqlSessionselectOne():执行 SQL 语句,最多得到一行记录,返回多余数据会报错 (实现类DefaultSqlSession源码底层设置的list.size() > 1抛异常) selectList():执行 SQL 语句,返回多行数据 selectMap():执行 SQL 语句,得到一个 Map 结果 insert():执行 insert 语句 update():执行 update 语句 delete():执行 delete 语句 commit():提交事务 rollback():回滚事务
-
MyBatis 底层是 JDBC ,使用PreparedStatement来执行指定的SQL
注意:SqlSession
对象不是线程安全的,使用步骤:
- 在方法的内部,执行 SQL 语句之前,先获取 SqlSession 对象
- 调用 SqlSession 的方法,执行 SQL 语句
- 关闭 SqlSession 对象,执行 sqlSession.close();
2.4、 工具类 MyBatisUtil
因为 SqlSession 对象不是线程安全的,所以对于 SqlSession 对象的获取方法只能是始终获取的是那一个对象
就像之前学习 JDBC 创建的工具类来获取 Connection 对象一样,需要用到静态代码块
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
factory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if (factory != null){
sqlSession = factory.openSession(); //自动提交事务 factory.openSession(true)
}
return sqlSession;
}
}
使用:
dao 接口 —》 接口实现类,实现类里面调用工具类 MyBatisUtil,并执行SQL语句 —》 测试实现类功能
3、MyBatis框架 Dao 代理
3.1、Dao代理实现数据库操作
3.1.1、传统 Dao 开发方式
mapper 文件:
<mapper namespace="com.dao.StudentDao">
<select id="selectStudentById" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
StudentDao 接口:
public interface StudentDao {
Student selectStudentById(Integer id);
int insertStudent(Student student);
}
StudentDaoImpl 接口实现类:
public class StudentDaoImpl implements StudentDao {
@Override
public Student selectStudentById(Integer id) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
String sqlId = "com.dao.StudentDao.selectStudentById";
Student student = sqlSession.selectOne(sqlId,id);
sqlSession.close();
return student;
}
@Override
public int insertStudent(Student student) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
String sqlId = "com.dao.StudentDao.insertStudent";
int rows = sqlSession.insert(sqlId, student);
sqlSession.commit();
sqlSession.close();
return rows;
}
}
测试(Service中调用):
@Test
public void test2(){
StudentDao studentDao = new StudentDaoImpl();
Student student = studentDao.selectStudentById(3);
System.out.println(student);
Student s = new Student(2,"樱桃","yt@qq.com",33);
int i = studentDao.insertStudent(s);
System.out.println("影响了"+i+"条数据");
}
3.1.2、Dao代理分析
dao 代理技术:
就是指由 mybatis 创建 StudentDao 接口的实现类 Proxy(StudentDaoImpl) 对象,完成对 sql 语句的执行,MyBatis 创建一个对象代替手动创建 dao 实现类的功能
在 StudentDaoImpl 实现类中,是通过两行关键代码实现 sql 语句的执行,如下
String sqlId = "com.dao.StudentDao.selectStudentById";
Student student = sqlSession.selectOne(sqlId,id);
在测试方法(Service)中,调用 dao 的方法如下:
StudentDao studentDao = new StudentDaoImpl();
Student student = studentDao.selectStudentById(3);
分析:
-
通过测试方法中 Student student = studentDao.selectStudentById(3);
能得到实现类中的
String sqlId = "com.dao.StudentDao.selectStudentById";
- 在测试方法中,通过对象 studentDao 反射能得到全限定类型名称,对象 studentDao 是 StudentDao 类型的,全限定名称为 com.dao.StudentDao
- 在测试方法中,方法名 selectStudentById 就是 mapper 文件中的标签 id
-
通过 dao 接口中的方法和 mapper 文件中的标签
能得到实现类中的
Student student = sqlSession.selectOne(sqlId,id);
- 根据 dao 接口中的返回值,分析调用哪个查询方法
如果返回一个对象,调用 sqlSession.selectOne()
如果返回 List ,调用 sqlSession.selectList() - 根据 mapper 文件中 update|delete|insert 等标签,调用 sqlSession.update() 等方法
- 根据 dao 接口中的返回值,分析调用哪个查询方法
使用 dao 代理要求:
1. mapper 文件中的 `namespace 属性值`,必须是 dao 接口的全限定名称
2. mapper 文件中 select|update|delete|insert 等标签的 `id 属性值`,必须是 dao 接口中对应方法的方法名称,需要是一模一样
3.1.3、MyBatis代理的实现
使用 SqlSession 对象的方法 getMapper(StudentDao.class)
例如:现在有 StudentDao 接口
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentById(3);
//上面代码中
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
等同于
StudentDao studentDao = new StudentDaoImpl();
就是获取到实现类对象
代码:
@Test
public void test3(){
// 1、获取 sqlSession 对象
SqlSession sqlSession = MyBatisUtil.getSqlSession();
// 2、获取 dao 的代理
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.selectStudentById(3);
System.out.println(student);
// 3、关闭 sqlSession 对象
sqlSession.close();
}
3.2、mapper与dao的参数
通过 java 程序把数据传入到 mapper 文件中的 SQL 语句,参数主要指 dao 接口方法的形参
3.2.1、parameterType
parameterType :表示参数的类型,指定 dao 方法的形参数据类型
这个形参的数据类型是给 MyBatis 使用,MyBatis 在给 sql 语句的参数赋值时使用
PreparedStatement.setXxx(参数位置,参数值)
- 第一个用法:使用 java 类型的全限定名称,parameterType=“java.lang.Integer”
- 第二个用法:使用 mybatis 定义的别名,parameterType=“integer”
- parameterType :mybatis 通过反射机制可以获取 dao 接口方法的参数类型,可以不写
下面使用的是 **java 类型的全限定名称 **
<!--
parameterType :指定 dao 接口形参的类型
属性值使用 java 类型的全限定名称或者 mybatis 定义的别名
mybatis执行的 SQL 语句是: SELECT * FROM `student` WHERE `id`= ?
? 是占位符,使用 JDBC 里面的PreparedStatement执行这样的sql语句
给 ? 位置赋值
参数是Integer,执行 setInt()
参数是String,执行setString()
-->
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
下面使用的是 mybatis 定义的别名
<select id="selectStudentById" parameterType="integer" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
下面不写:
<select id="selectStudentById" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
3.2.2、仅有一个简单类型参数
简单类型: 指的是 基本数据类型、String类型
接口方法参数仅有一个简单参数:
接口:
//dao 接口方法的形参是一个简单类型参数
Student selectStudentByName(String name);
mapper 文件:
<!--
dao 接口方法里面是一个简单类型参数
mapper 文件获取这个参数,使用 #{任意字符}
-->
<select id="selectStudentByName" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{aaaa}
</select>
3.2.3、有多个简单类型参数
简单类型: 指的是 基本数据类型、String类型
接口方法参数有多个简单参数:使用注解 @Param
接口:
/**
* dao 接口方法的形参是多个简单类型参数
* 需要使用mybatis框架提供的注解 @Param 命名参数
* 位置:在形参类型的前面
* 属性: value 自定义参数名称,名称与mapper文件中#{}里面的名称一致
*/
Student selectStudentByNameOrAge(@Param(value = "myname")String name,
@Param(value = "myage")Integer age);
mapper 文件:
<!--
dao 接口方法里面是多个简单类型参数
当使用了 @Param 命名参数后,例如 @Param(value = "myname")
在 mapper 文件中,使用 #{命名的参数名},例如 #{myname}
-->
<select id="selectStudentByNameOrAge" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{myname} or `age`= #{myage}
</select>
接口方法参数有多个简单参数:按位置传递参数(了解)
参数位置:dao 接口中方法的形参列表,从左往右,位置是:0、1、2…
语法格式:#{arg0},#{arg1}
接口:
Student selectStudentByNameOrAge(Integer age, String name);
mapper 文件:
<select id="selectStudentByNameOrAge" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{arg1} or `age`= #{arg0}
</select>
3.2.4、对象类型参数
方法的形参是一个 java 对象,这个 java 对象表示多个参数,使用对象的属性值作为参数使用
使用简单的语法获取对象属性 #{属性名}
java 对象:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
}
@Data
public class QueryParam {
private String p1;
private Integer p2;
}
接口:
/**
* 使用一个 java 对象作为参数,对象的属性有set、get方法
*/
int insertStudent(Student student);
Student selectStudentByParam(QueryParam queryParam);
mapper 文件:
<!--
dao 接口方法里面是一个 java 对象作为参数,使用对象的属性作为参数值使用
简单的语法:#{属性名},mybatis 调用此属性的 get 方法获取属性值
-->
<insert id="insertStudent">
INSERT INTO `student`(`name`,`email`,`age`) VALUES(#{name},#{email},#{age})
</insert>
<select id="selectStudentByParam" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{p1} or `age`= #{p2}
</select>
使用复杂的语法获取对象属性 #{属性名,javaType=属性类型,jdbcType=数据库参数类型}
使用java对象传递参数,对象的属性值就是SQL需要的参数类型值
语法格式: #{属性名,javaType=属性类型,jdbcType=数据库参数类型}
- 对象的属性类型就是全限定类型名称
- 数据库参数类型需要参考 MyBatis 的文档 mybatis-3.5.1.pdf 第 43 页 4.1.5.4 小节,如下:
接口:
Student selectStudentByObject(Student student);
mapper 文件:
<select id="selectStudentByObject" resultType="com.domain.Student">
SELECT * FROM `student` WHERE
`name`= #{name,javaType=java.lang.String,jdbcType=VARCHAR}
or
`age`= #{age,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>
3.2.5、Map 类型参数(了解)
map 作为 dao 接口的参数,使用 key 获取参数值,在 mapper 文件中,语法格式 #{key}
测试使用的时候才能确定 Map 的key名称,不好用
接口:
//使用 Map 作为参数
List<Student> selectStudentByMap(Map<String,Object> map);
mapper 文件:
<!--
dao 接口方法里面是使用 Map 作为形参
在 mapper 文件中获取 map 的值,是通过 key 来获取的 #{key}
-->
<select id="selectStudentByMap" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{key1} or `age`= #{key2}
</select>
测试:
@Test
public void test3(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Map<String,Object> map = new HashMap<>();
map.put("key1","小草莓");
map.put("key2",12);
List<Student> students = studentDao.selectStudentByMap(map);
students.forEach(System.out::println);
sqlSession.close();
}
3.3、 # 与 $
3.3.1、 #占位符
语法:#{字符}
mybatis 处理 #{} ,底层使用的jdbc对象是 PreparedStatement 对象
<select id="selectStudentById" parameterType="integer" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
mybatis创建 PreparedStatement 对象,执行 SQL 语句
String sql = "SELECT * FROM student WHERE id = ?";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setInt( 1, 2); //传递参数
ResultSet rs = ps.executeQuery(); //执行 SQL 语句
#{} 占位符特点:
- 使用的是 PreparedStatement 对象,执行sql语句,效率高
- 使用的是 PreparedStatement 对象,能避免sql注入,sql语句执行更安全
- #{} 常常作为列值使用,位于等号右侧,#{} 位置的值和数据类型有关
3.3.2、 $占位符
语法:${字符}
mybatis 执行 ${} 占位符的sql语句
<select id="selectStudentById" parameterType="integer" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= ${studentId}
</select>
${} 表示字符串连接,把SQL语句的其他内容和 ${} 内容使用字符串(+)连接的方式连接在一起
String sql = "SELECT * FROM student WHERE id = " + "2";
mybatis创建 Statement 对象,执行 SQL 语句
Statement s = conn.createStatement(sql);
ResultSet rs = s.executeQuery(); //执行 SQL 语句
${} 占位符特点:
- ${} 使用 Statement 对象,执行sql语句,效率低
- 使用字符串连接的方式,有 SQL注入风险,有代码安全问题
- ${} 数据是原样使用,不会区分数据类型
- ${} 常用作表名或列名,在能保证数据安全的情况下使用 ${}
$占位符使用的案例:
接口:
// ${} 占位符的使用,需要使用 @Param 命名
List<Student> selectStudent(@Param(value = "myname") String name);
mapper 文件:
<select id="selectStudent" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= ${myname}
</select>
失败测试:
List<Student> students = studentDao.selectStudent("zs");
students.forEach(System.out::println);
下面可以看到 ${} 数据是原样使用
相当于直接复制到 SQLyog 去执行,发现需要 引号 ,因为是字符串
成功测试:(说明有SQL注入风险)
List<Student> students = studentDao.selectStudent("'zs'");
students.forEach(System.out::println);
3.3.3、 $占位符表示表名或列名
所以只可以使用 $占位符 表示表名或列名
在 mysql 里面排序的代码应该是:
SELECT * FROM `student` ORDER BY id
而不是:
SELECT * FROM `student` ORDER BY "id"
通用的排序操作
接口:
List<Student> queryStudent(@Param(value = "myname") String s
, @Param(value = "colName") String name);
mapper 文件:
<select id="queryStudent" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`= #{myname} order by ${colName}
</select>
测试:
List<Student> students = studentDao.queryStudent("zs","id");
students.forEach(System.out::println);
3.4、封装输出结果
封装输出结果:MyBatis 执行 SQL 语句,得到 ResultSet,转换为 java 对象
3.4.1、resultType
resultType 属性:在执行 select 时使用,作为 select 标签的属性出现
resultType :表示结果类型,mysql执行 SQL 语句,得到 java 对象的类型,属性值有两种
1. Java类型的全限定名称
2. 使用别名
3.4.1.1、对象类型
dao 接口:
Student selectStudentById(Integer id);
mapper 文件:
<select id="selectStudentById" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
resultType :上面使用的是java类型的全限定名称,表示 mybatis 执行sql,把ResultType中的数据转为Student类型的对象。MyBatis会做以下操作:
1、调用com.domain.Student的无参构造器,创建对象
Student student = Class.forName("Student").newInstance(); //使用反射创建对象
2、同名的列赋值给同名的属性
Student.setInt(rs.getInt("id"));
Student.setString(rs.getString("name"));
3、得到java对象,如果dao接口返回值是List集合,mybatis把Student放入List集合
所以执行 Student mystudent = studentDao.selectStudentById(1); 得到数据库中 id=1 这行数据
这行数据的列值,赋值给mystudent对象的属性,得到mystudent这个对象,就是得到 id=1 这行数据
测试:
Student student = studentDao.selectStudentById(12);
注意:
resultType 会默认将同名的列赋值给同名的属性,这意味着,如果属性名与数据库列名不一致,就无法进行赋值
TestStudent对象如下:
@Data
public class TestStudent {
private Integer ttid;
private String ttname;
private String email;
private Integer age;
}
dao 接口:
TestStudent selectStudentById(@Param(value = "stuid")Integer id);
mapper 文件:
<select id="selectStudentById" resultType="com.domain.TestStudent">
SELECT * FROM `student` WHERE `id`= #{stuid}
</select>
测试结果:
输出的对象信息,对于与列名不同的属性名,不会有值
3.4.1.2、简单类型
dao 接口:
Long selectCount();
mapper 文件:
<!--
执行 SQL 语句,得到的是一个值(一行一列)
resultType="java.lang.Long"
-->
<select id="selectCount" resultType="long">
SELECT count(*) FROM `student`
</select>
3.4.1.3、Map 类型
注意:
SQL执行得到的是一行记录,才可以使用
dao 接口:
//查询结果返回是一个Map
Map<Object, Object> selectMap(Integer id);
mapper 文件:
<!--
执行SQL语句,得到一个Map结构数据,mybatis执行SQL,把ResultSet转为map
SQL执行结果,列名作为map的key,列值作为对应的value
只有当SQL执行得到的是一行记录,才可以使用,否则会报错
-->
<select id="selectMap" resultType="java.util.HashMap">
SELECT id,name FROM `student` WHERE `id`= #{stuid}
</select>
测试:
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Map<Object, Object> map = studentDao.selectMap(3);
System.out.println(map); //{name=大西瓜, id=3}
System.out.println(map.get("name")); //大西瓜
System.out.println(map.get("id")); //3
3.4.1.4、resultType 练习题
练习题:
输入省份 id,得到省份id、省份name、城市id、城市name
直接使用 mysql 查询,代码如下:
SELECT
p.`id` pid,
p.`name` pname,
c.`id` cid,
c.`name` cname
FROM
`province` p
INNER JOIN `city` c
ON c.`provinceid` = p.`id`
WHERE p.`id` = 1
使用 MyBatis
ProAndCity 类定义如下:
@Data
public class ProAndCity {
private Integer pid;
private String pname;
private Integer cid;
private String cname;
}
dao 接口:
List<ProAndCity> selectProAndCityById(@Param(value = "proid")Integer id);
mapper 文件:
<select id="selectProAndCityById" resultType="com.domain.ProAndCity">
SELECT p.`id` pid,p.`name` pname,c.`id` cid,c.`name` cname
FROM `province` p INNER JOIN `city` c ON c.`provinceid`=p.`id`
WHERE p.`id` = #{proid}
</select>
测试:
@Test
public void test1(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<ProAndCity> proAndCities = studentDao.selectProAndCityById(1);
System.out.println(proAndCities);
sqlSession.close();
}
输出结果:
[
ProAndCity(pid=1, pname=江苏, cid=1, cname=南京),
ProAndCity(pid=1, pname=江苏, cid=2, cname=苏州)
]
3.4.2、resultMap
resultMap :结果映射。自定义列名和 java 对象属性的对应关系,常用在列名和属性名不同的情况
使用步骤:
- 先定义 resultMap 标签,指定列名和属性名的对应关系
- 在 select 标签使用 resultMap 属性,指定上面定义的 resultMap 标签的 id 值
TestStudent对象如下:
@Data
public class TestStudent {
private Integer ttid;
private String ttname;
private String email;
private Integer age;
}
dao 接口:
TestStudent selectStudentById(@Param(value = "stuid")Integer id);
mapper 文件:
<!-- 使用 resultMap 标签定义列和属性的关系 -->
<!--
定义 resultMap
id :给 resultMap 的映射关系起个名称,唯一值
type :java 类型的全限定名称
-->
<resultMap id="myMap" type="com.domain.TestStudent">
<!-- 定义列名和属性名的对应关系,列名和属性名一致的不用定义 -->
<!--主键列使用 id 标签-->
<id column="id" property="ttid"/>
<!--非主键列使用 result 标签-->
<result column="name" property="ttname"/>
</resultMap>
<!-- 使用 resultMap 属性,指定映射关系的 id 值-->
<select id="selectStudentById" resultMap="myMap">
SELECT * FROM `student` WHERE `id`= #{stuid}
</select>
测试结果:
3.5、自定义别名
自定义别名步骤:
- 在主配置文件中,使用
typeAliases
标签声明别名,注意位置在设置日志之后 - 在 mapper 文件中,
resultType="别名"
3.5.1、第一种: 使用 typeAlias 标签
声明别名, MyBatis 主配置文件中
<!--声明别名-->
<typeAliases>
<!--
第一种语法格式:
type :java类型的全限定名称(自定义类型)
alias : 自定义别名
优点:别名自定义
确定:每个类型必须单独定义
-->
<typeAlias type="com.domain.Student" alias="stu"/>
</typeAliases>
mapper 文件中
<select id="selectStudentById" resultType="stu">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
3.5.2、第二种:使用 package 标签
如果有重复类名会报错
声明别名, MyBatis 主配置文件中
<!--声明别名-->
<typeAliases>
<!--
第二种方式:
name :包名,mybatis 会把这个包中所有类名作为别名(不用区分大小写)
优点:使用方便,一次性给多个类定义别名
缺点:别名不能自定义,必须是类名,如果有重复类名会报错
-->
<package name="com.domain"/>
</typeAliases>
mapper 文件中
<select id="selectStudentById" resultType="student">
SELECT * FROM `student` WHERE `id`= #{id}
</select>
当出现以下情况,执行时候会报错
3.6、列名和属性名不一致
在查询数据的时候,当数据库的列名与 想封装数据的java对象的属性名 布依族吧的时候
解决方法:
- 使用 resultMap :自定义列名和属性名称对应关系
- 使用 resultType :使用列别名,让别名和 java 对象的属性名称一致(详见3.4.1.4、resultType 练习题)
3.7、like
在学习 mysql 的时候,使用 like 来进行模糊查询,那么在 mybatis 中如何表现?
3.7.1、第一种方式
在 java 程序中,把 like 的内容组装好,把这个内容传入到 SQL 语句
WHERE name like #{name}
,String name = "%大%";
dao 接口:
//like第一种方式
List<Student> queryLikeOne(@Param(value = "name") String name);
mapper 文件:
<select id="queryLikeOne" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name`like #{name}
</select>
测试:
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
String name = "%大%";
List<Student> students = studentDao.queryLikeOne(name);
students.forEach(System.out::println);
sqlSession.close();
}
执行结果:
3.7.2、第二种方式
SQL 语句 like 的格式为:WHERE name like "%"空格#{name}空格"%"
dao 接口:
//like第二种方式
List<Student> queryLikeTwo(@Param(value = "name") String name);
mapper 文件:
<select id="queryLikeTwo" resultType="com.domain.Student">
SELECT * FROM `student` WHERE `name` like "%" #{name} "%"
</select>
测试:
String name = "大";
List<Student> students = studentDao.queryLikeTwo(name);
4、MyBatis框架动态 SQL
动态 SQL :同一个 dao 方法,根据不同的条件可以表示不同的 SQL 语句,主要是 where 部分有变化
使用 mybatis 提供的标签,实现动态 SQL ,主要使用 if、where、foreach、sql
使用动态 SQL 的时候,dao 方法的形参使用 java 对象
什么时候使用动态 SQL ?
当需要实现多条件查询的时候,比如可以根据姓名和年龄查询信息,同时还要实现年龄为空,仅使用姓名也可以查询信息;或者姓名为空,仅使用年龄也可以查询信息
4.1、if 标签
语法:
<if test="boolean判断结果">
sql 代码
</if>
在 mapper 文件中,使用如下:
当条件满足的时候,会将 if 标签内的语句直接加在当前 SQL 语句后面
比如,当条件全部满足的时候,就是SELECT * FROM student where name = #{name} or age > #{age}
<select id="selectStudent" resultType="com.domain.Student">
SELECT * FROM `student` where
<if test="name!=null and name!=''">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
dao 接口:
// if
List<Student> selectStudent(Student student);
测试:
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(null,"zs",null,88);
List<Student> students = studentDao.selectStudent(student);
students.forEach(System.out::println);
sqlSession.close();
}
执行结果如下:
注意,此时会有两个问题:
-
对于 test 里面的判断语句的 大于小于号,需要使用实体符号替换
-
因为当test的条件满足的时候,是直接将语句拼接在SQL语句后面,所以当有多个 if 标签的时候,if语句之间需要有 and、or 连接词
-
如果每一句都有 and、or 连接词,但是第一个if标签的test判断不通过的时候,就会出现
SELECT * FROM student where or age > #{age}
,报错
解决办法:
既然要保证紧挨着 where 关键字的语句没有 and、or 连接词
不妨自己写一个语句紧挨着 where 关键字,然后在后面的 if 标签里面每个句子都是用连接词,如下:
<select id="selectStudent" resultType="com.domain.Student">
SELECT * FROM `student` where 1!=1
<if test="name!=null and name!=''">
or name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
4.2、where 标签
使用 if 标签时,容易引起 SQL 语句语法错误。所以使用 where 标签来解决 if 产生的语法问题
where 标签内是一个或多个 if 标签,每个if标签的语句都要使用 and、or 连接词:
where 标签会删除和它最近的 and、or 连接词;
当有一个 if 标签判断条件为 true 时,where 标签会转为 WHERE
关键字拼接在 SQL 语句后面;
当没有任何 if 标签条件判断为 true 时,会忽略整个 where 标签;
语法:
<where>
<if test="条件1">sql代码1</if>
<if test="条件2">sql代码2</if>
</where>
dao 接口:
// where
List<Student> selectWhere(Student student);
mapper 文件中:
<select id="selectWhere" resultType="com.domain.Student">
SELECT * FROM `student`
<where>
<if test="name!=null and name!=''">
or name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</where>
</select>
测试:
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(null,"",null,88);
List<Student> students = studentDao.selectWhere(student);
students.forEach(System.out::println);
sqlSession.close();
}
执行结果:
4.3、foreach 标签
foreach 标签用于实现对于数组与集合的遍历,一般使用在 IN 语句中,需要注意:
collection 表示要遍历集合的类型,list、array 等
open、close、separator 是对遍历内容的 SQL 拼接
语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员"
separator="集合成员之间的分隔符">
#{item}
</foreach>
标签属性:
collection:表示循环的对象是数组、集合
如果 dao 接口方法形参是数组,使用collection="array"
如果 dao 接口方法形参是集合,使用collection="list"
open:循环开始时的字符 sql.append("("); //循环之前
close:循环结束时的字符 sql.append(")"); //循环之后
item:集合成员,自定义变量 Integer item = idlist.get(i); // 集合中的成员 item
separator:成员之间的分隔符 sql.append(","); //集合成员之间的分隔符
#{item}:获取集合成员的值
4.3.1、手动实现循环
当需要查询 id 在集合 idlist{19,22,23} 中的学生信息,即SELECT * FROM student WHERE id IN(19,22,23)
@Test
public void test2(){
List<Integer> idlist = new ArrayList<>();
idlist.add(19);
idlist.add(22);
idlist.add(23);
//查询集合中 id 的学生信息
// SELECT * FROM student WHERE id IN(19,22,23)
StringBuffer sql = new StringBuffer("");
sql.append("SELECT * FROM student WHERE id IN");
// 使用循环,将集合中的数据追加到 sql 字符串中
sql.append("("); //循环之前
for (int i = 0; i < idlist.size(); i++) {
Integer item = idlist.get(i); // 集合中的成员 item
sql.append(item); //添加成员到 sql 字符串
sql.append(","); //集合成员之间的分隔符
}
sql.deleteCharAt(sql.length()-1); //删除最后多余的逗号,
sql.append(")"); //循环之后
System.out.println(sql);
}
输出结果:
SELECT * FROM student WHERE id IN(19,22,23)
4.3.2、遍历 List<简单类型>
dao 接口:
// foreach --遍历 List<简单类型>
List<Student> selectForeachOne(List<Integer> idlist);
mapper 文件:
<select id="selectForeachOne" resultType="com.domain.Student">
SELECT * FROM `student` where id in
<foreach collection="list" open="(" close=")" item="myid" separator=",">
#{myid}
</foreach>
</select>
测试:
@Test
public void testSelectForeachOne(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Integer> idlist = new ArrayList<>();
idlist.add(19);
idlist.add(22);
idlist.add(23);
List<Student> students = studentDao.selectForeachOne(idlist);
students.forEach(System.out::println);
sqlSession.close();
}
注意:
-
因为传入的是集合,需要判断集合是否为 null,如果在 mapper 文件中使用 if 标签,如下
<select id="selectForeachOne" resultType="com.domain.Student"> SELECT * FROM `student` WHERE id IN <if test="list != null"> <foreach collection="list" open="(" close=")" item="myid" separator=","> #{myid} </foreach> </if> </select> 但当集合为 null 的时候,执行的SQL语句就是 SELECT * FROM `student` where id in,有语法错误
-
如果将 where 语句也放在 if 标签里面,如下
<select id="selectForeachOne" resultType="com.domain.Student"> SELECT * FROM `student` <if test="list != null"> WHERE id IN <foreach collection="list" open="(" close=")" item="myid" separator=","> #{myid} </foreach> </if> </select> 1、当集合不为 null但是集合内为空的时候,就会执行if标签,但是遍历没有数据 执行的SQL语句是 SELECT * FROM `student` where id in,有语法错误 2、且当集合为 null的时候,会查询出所有学生信息 执行的SQL语句是 SELECT * FROM `student`,存在信息泄露问题
解决方法:
<select id="selectForeachOne" resultType="com.domain.Student">
SELECT * FROM `student`
<if test="list != null and list.size > 0">
WHERE id IN
<foreach collection="list" open="(" close=")" item="myid" separator=",">
#{myid}
</foreach>
</if>
</select>
4.3.2、遍历 List<对象类型>
dao 接口:
// foreach --遍历 List<对象类型>
List<Student> selectForeachTwo(List<Student> studentList);
mapper 文件:
<select id="selectForeachTwo" resultType="com.domain.Student">
SELECT * FROM `student`
<if test="list != null and list.size > 0">
where id in
<foreach collection="list" open="(" close=")" item="stu" separator=",">
#{stu.id}
</foreach>
</if>
</select>
测试:
@Test
public void testSelectForeacTwo(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = new ArrayList<>();
studentList.add(new Student(22,null,null,null));
studentList.add(new Student(23,null,null,null));
List<Student> students = studentDao.selectForeachTwo(studentList);
students.forEach(System.out::println);
sqlSession.close();
}
4.4、代码片段 sql 标签
sql 标签表示一段 SQL 代码,可以是表名、几个字段、WHERE条件等都可以,可在其他地方复用 sql 标签的内容
使用方式:
1、在mapper 文件中定义sql代码片段 <sql id="唯一字符串"> 部分sql语句 </sql>
2、在其他位置,使用 <include>标签引用某个代码片段
示例:
<!-- 定义代码片段 -->
<sql id="ss">
SELECT * FROM `student`
</sql>
<sql id="sl">
name,email
</sql>
<!-- 使用 -->
<!-- 表示 SELECT * FROM `student` where name = #{name} -->
<select id="selectStudent" resultType="com.domain.Student">
<include refid="ss"/> where name = #{name}
</select>
<!-- 表示 SELECT name,email FROM `student` where name = #{name} -->
<select id="queryStudent" resultType="com.domain.Student">
SELECT <include refid="sl"/> FROM `student` where name = #{name}
</select>
5、主配置文件
MyBatis配置文件两大类:1、主配置文件; 2、 mapper 文件
- 主配置文件:提供MyBatis全局设置,包含日志、数据源、mapper文件位置
- mapper 文件:写 sql 语句的,一个数据库表对应一个 mapper 文件
5.1、settings
settings 是全局设置,影响整个MyBatis的运行,一般使用默认值就可以了,用的最多的是日志设置
一个配置完整的 settings 元素的示例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
5.2、typeAliases 类型别名
<typeAliases>
<!--
第一种语法格式:
type :java类型的全限定名称(自定义类型)
alias : 自定义别名
优点:别名自定义
确定:每个类型必须单独定义
-->
<typeAlias type="com.domain.Student" alias="stu"/>
<typeAlias type="com.vo.QueryParam" alias="quep"/>
<!--
第二种方式:
name :包名,mybatis 会把这个包中所有类名作为别名(不用区分大小写)
优点:使用方便,一次性给多个类定义别名
缺点:别名不能自定义,必须是类名,如果有重复类名会报错
-->
<package name="com.domain"/>
<package name="com.vo"/>
</typeAliases>
5.3、配置环境
environments
:环境标签,在该标签里面可以配置多个 environment
属性:default ,必须是某个 environment 的 id 属性值,表示 mybatis 默认连接的数据库
environment
:表示一个数据库的连接信息
属性:id 自定义的环境的标识,唯一值
transactionManager
:事务管理器
属性:type 表示事务管理器的类型
属性值: 1) JDBC ,使用 Connection 对象,由 MyBatis 自己完成事务的处理
2) MANAGED ,管理,表示把事务的处理交给容器实现(由其他软件完成事务提交与回滚)
dataSource
:数据源,创建 Connection 对象,连接数据库
属性:type 数据源的类型
属性值:1) POOLED ,mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象, 使用连接池
2)UNPOOLED ,不使用连接池,mybatis创建UnPooledDataSource类,每次执行SQL语句先 创建Connection对象,再执行SQL语句,最后关闭Connection
3) JNDI ,java的命名和目录服务
<environments default="mydb">
<environment id="mydb">
<transactionManager type="JDBC"/>
<!-- 配置数据源:创建 Connection 对象 -->
<dataSource type="POOLED">
<!--driver 驱动信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/book"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
5.4、使用数据库属性配置文件
需要把数据库的配置信息放到一个单独文件中,独立管理。文件扩展名是 properties ,在这个文件中,使用自定义 key=value 的格式表示数据
使用步骤:
-
在 resources 目录中,创建 xxx.properties
-
在文件中,使用 key=value 的格式定义数据
jdbc.username=root
-
在 mybatis 主配置文件中,使用 properties 标签引用外部的属性配置文件
-
在使用值的位置,使用 ${key} 获取 key 对应的 value (等号右侧的值)
示例:
resources/jdbc.properties 文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/book
jdbc.username=root
jdbc.password=admin
resources/mybatis.xml 主配置文件
<environments default="mydb">
<environment id="mydb">
<transactionManager type="JDBC"/>
<!-- 配置数据源:创建 Connection 对象 -->
<dataSource type="POOLED">
<!--driver 驱动信息-->
<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>
5.5、 mapper 标签
使用 mapper 指定其他 mapper 文件的位置
mapper 标签使用的格式有两个常用的方式
<!--
指定其他 mapper 文件的位置,目的是找到其他文件的 SQL 语句
-->
<mappers>
<!-- 第一种方式,resource="mapper文件的路径"
使用 mapper标签的 resource 属性指定其他 mapper 文件的路径,这个路径是从 target/classes 路径开始的
使用注意:
1、resource属性值,mapper文件的路径是使用 / 分割路径
2、一个 mapper标签指定一个 mapper 文件
优点:文件清晰,加载的文件是明确的,文件的位置比较灵活
缺点:文件较多时,代码量会比较大,管理难度大
-->
<mapper resource="com/dao/StudentDao.xml"/>
<!-- 第二种方式,使用 <package name="mapper文件所在的包名"/>
特点:
1、resource属性值,mapper文件的路径是使用 . 分割路径
2、将这个包中所有 mapper 文件,一次加载
使用要求:
1、mapper文件和 dao 接口在同一目录
2、mapper文件和 dao 接口名称完全一样
-->
<package name="com.dao"/>
</mappers>
6、PageHelper分页插件
PageHelper 做数据分页,会在你的 select 语句后面加入分页的SQL内容
比如如果使用 mysql 数据库,它就会在 select * from student 后面加入 limit 语句
使用步骤:
-
加入 pagehelper 依赖
<!-- pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.0</version> </dependency>
-
在 mybatis 主配置文件,加入 plugin 声明(environments元素前)
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
-
在 select 语句之前,调用
PageHelper.startPage(页码,每页大小)
@Test public void testPage(){ // 1、获取 SqlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 2、获取 dao 的代理 StudentDao studentDao = sqlSession.getMapper(StudentDao.class); //调用 PageHelper 的方法 PageHelper.startPage(2,2); List<Student> students = studentDao.queryStudent(); students.forEach(System.out::println); // 3、关闭 SqlSession sqlSession.close(); }
PageHelper 做数据分页,会在你的 select 语句后面加入分页的SQL内容
mapper 文件:
<select id="queryStudent" resultType="com.domain.Student">
SELECT * FROM `student`
</select>
dao 接口:
List<Student> queryStudent();
7、获取插入数据生成的主键(了解)
在开发中,如果需要获取到数据库中自动生成的主键,那么使用 MyBatis 应该如何实现呢?
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO `user`(`name`,`age`,`salary`) VALUES(#{name},#{age},#{salary})
</insert>
useGeneratedKeys:是否要获取自动生成的主键
keyColumn:表中的主键列
keyProperties:主键列对应的 User 类的属性
以上就表示从获取哪个列的值封装到哪个属性中
通过上面的配置,在执行了保存操作后,mybatis 会自动将主键值封装到传递进来的 User 对象的 id 属性中
所以,此时的 User 对象的 id 属性就有值了(在保存之前是没有的)
parameterType :
该属性表示参数类型,此处插入操作可以不用写,因为插入操作调用的时候用户会传入对象,由MyBatis自己通过用户传入的对象去推导
在实现类中获取 id 值,或者在测试类中获取 id 值都可,但是注意要在事务提交之后进行获取才行
测试类中:
实现类中:
执行结果: