一.Mybatis简介
1.1 Mybatis概述
MyBatis最初是Apache的一个开源项目iBatis, 2010年6月
这个项目由Apache Software Foundation迁移到了
Google Code。随着开发团队转投Google Code旗下,
iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到
Github。
MyBatis 是一款优秀的持久层框架,用于简化 JDBC 开
发。它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获
取结果集的工作。MyBatis 可以通过简单的 XML 或注解来
配置和映射原始类型、接口和 Java POJO(Plain Old Java
Objects,普通老式 Java 对象)为数据库中的记录。
官网:https://mybatis.org/mybatis-3/zh/index.html
1.2 浅谈JDBC代码
public class DemoTest {
public static void main(String[] args) {
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2. 获取Connection连接
String url = "jdbc:mysql:///db1?
useSSL=false";
String uname = "root";
String pwd = "1234";
Connection conn =
DriverManager.getConnection(url, uname, pwd);
// 接收输入的查询条件
String gender = "男";
// 定义sql
String sql = "select * from tb_user
where gender = ?";
// 获取pstmt对象
PreparedStatement pstmt =
conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1,gender);
// 执行sql
ResultSet rs = pstmt.executeQuery();
// 遍历Result,获取数据
User user = null;
ArrayList<User> users = new ArrayList<>();
while (rs.next()) {
//获取数据
int id = rs.getInt("id");
String username =
rs.getString(“username”);
String password =
rs.getString(“password”);
//创建对象,设置属性值
user = new User();
user.setId(id);
user.setUsername(username);
user.setPassword(password);
user.setGender(gender);
//装入集合
users.add(user);
}
//释放资源
rs.colse();
pstmt.colse();
conn.close();
}
}
jdbc这个步骤非常的麻烦;所以我们用mybatis框架来代替jdbc
硬编码
注册驱动、获取连接。连接数据库的四个基本信息,以
后如果要将Mysql数据库换成其他的关系型数据库的
话,这四个地方都需要修改,如果放在此处就意味着要
修改我们的源代码。
如果表结构发生变化,SQL语句就要进行更改。这也不
方便后期的维护。
操作繁琐
手动设置参数
手动封装结果集
MyBatis:SQL 和 Java 编码分开,功能边界清晰。Java代码专
注业务、SQL语句专注数据
MyBatis:免除了几乎所有的 JDBC 代码以及设置参数和获取
结果集的工作
1.3 框架名词解释
框架就是一个半成品软件,是一套可重用的、通用的、软
件基础代码模型
在框架的基础之上构建软件编写更加高效、规范、通用、
可扩展
二.快速入门(基于Mybatis3方式)
2.1 入门案例实现步骤
创建数据库和表
创建模块,导入坐标
实体类准备
编写Mybatis核心配置文件,数据库的连接信息等
编写Mapper接口
编写 SQL 映射文件,编写SQL语句
测试
创建数据库和表:
CREATE TABLE t_emp(
emp_id INT primary key AUTO_INCREMENT,
emp_name CHAR(100),
emp_salary DOUBLE(10,5)
);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("张三",200.33);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("李四",200.44);
INSERT INTO t_emp(emp_name,emp_salary)
VALUES("王五",200.55);
创建模块,导入坐标
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次
不需要导入连接池,mybatis自带! -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
准备实体
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
编写Mybatis核心配置文件
替换连接信息 解决硬编码问题
在模块下的 resources 目录下创建mybatis的配置文件
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration表示mybatis框架的核心配置文件的根标
签,配置-->
<configuration>
<!--
environments:表示当前mybatis框架的环境:开发
测试环境等
一个environments标签下面可以书写多个
environment
一个environment标签代表一个环境
-->
<environments default="development">
<environment id="development">
<!--
事务管理,这里先使用mybatis框架的默认
管理type="JDBC",实际开发中
mybatis框架的事务由spring框架
-->
<transactionManager type="JDBC">
</transactionManager>
<!--
数据源即数据库连接池,不用修改,使用
mybatis默认的数据库连接池
实际开发中由spring管理,这就是
type="POOLED"
-->
<dataSource type="POOLED">
<property name="driver"
value="com.mysql.cj.jdbc.Driver"/>
<property name="url"value="jdbc:mysql://localhost:3306/ssm_01"/>
<property name="username"value="root"/>
<property name="password"value="123456"/>
</dataSource>
</environment>
</environments>
<!--加载映射配置文件-->
<mappers>
<mapper resource="EmployeeMapper.xml">
</mapper>
</mappers>
</configuration>
编写Mapper接口
Mybatis 中的 Mapper 接口相当于以前的 Dao。但是区别在
于,Mapper 仅仅只是建接口
package com.ll.mapper;
import com.ll.pojo.Employee;
import java.util.List;
//接口只规定方法,参数和返回值!映射配置文件中编写具体SQL
语句!
public interface EmployeeMapper {
public List<Employee> findAll();
}
编写 SQL 映射文件
统一管理sql语句,解决硬编码问题
在模块的 resources 目录下创建映射配置文件
EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间 该映射配置文件和哪个Mapper接口
进行映射绑定-->
<mapper
namespace="com.lzw.mapper.EmployeeMapper">
<!--id:唯一标识,映射接口的方法 resultType:输出的参数类型
-->
<select id="findAll"
resultType="com.lzw.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
</select>
</mapper>
test测试代码
public class DemoTest {
//入门案例
@Test
public void test01() throws IOException {
//读取核心配置文件
InputStream in =
Resources.getResourceAsStream("mybatis-config.xml");
//构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象获取
SqlSession对象(就是connection)
SqlSession sqlSession =
sqlSessionFactory.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//处理结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
}
2.2 Lombok插件的使用(简化代码)
使用Lombok注解就可以省略生成getXxx()、setXxx()方法、
toString()方法、构造器等固定格式代码的繁琐操作,提高开
发效率。包括Logger日志对象。
Lombok原理:Lombok是将自动生成的代码织入字节码文件
中,从而实现:源代码没有,但是字节码文件有——毕竟我们
最终运行的是字节码文件,只要字节码文件中有即可。而这个
过程因为要参与源文件编译,所以需要安装IDEA插件。
Lombok安装
加入依赖
在resources创建xml文件将依赖复制到xml文件中去
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
注解功能介绍
使用Lombok
package com.lzw.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
}
2.3 日志框架(便于调试)
2.3.1 用日志打印替代sout
sout有什么问题
System.out对象是一个输出流对象,所以控制台输出信息
本质上是I/O操作。而I/O操作是项目运行过程中两大性能
瓶颈之一。
项目上线时,希望把所有(或一部分)sout打印关闭,但
是只能手动一个一个查找,耗费开发人员的极大精力,因
为sout的无度使用会使它分散在项目的各个角落。
使用[日志框架]的好处
设定级别,统一管理。日志框架会按照事件的严重程度来
划分级别,例如:
错误(Error):表示程序运行出错,比如抛异常等情
况。
警告(Warning):表示程序运行过程中有潜在风险,
但此时并没有报错。
信息(Info):表示程序运行过程中完成了一个关键动
作,需要以程序运行信息的形式告知开发者。
试(Debug):表示程序运行过程中更加细致的信
息,协助程序员调试程序。
灵活指定输出位置
使用日志框架不一定是打印到控制台,也可以保存到文
件中或者保存到数据库。这就看具体的项目维护需求。
自定义日志格式
打印日志数据可以使用日志框架的默认格式,也可以根据需要定制。
基于日志分析问题
将来我们开发的应用系统中,不仅包含Java代码,还有
很多中间件服务器。任何子系统出现故障我们都是通过
日志来定位问题、分析故障原因。甚至更复杂的系统还
会专门开发日志子系统,在主系统出现问题时抓取日志
数据供维护人员参考。而日志数据必须要有确定格式才
便于格式化和抓取,这肯定不是随意写sout就能实现
的。
通过在配置文件中指定某一个日志级别来控制系统要打印的内
容。日志框架会打印当前指定级别的日志和比当前指定级别更
严重的级别的日志。
例如在开发阶段,我们指定debug级别,项目上线修改成info
级别,那么所有debug级别的日志就都不打印了,不需要到项
目代码中一个一个修改,非常方便。
2.3.2 Java日志体系演变
门面:类似于标准层、接口层
实现
最佳拍档
门面:SLF4J
实现:logback
2.3.3 日志用法
依赖导入
<!-- 日志 会自动传递slf4j门面-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
引入配置
Logback要求配置文件名称必须是logback.xml,存放路径在
main/resources目录下。
通过配置文件,可以配置输出格式、输出级别、输出位置等!
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置,ConsoleAppender表示输出
到控制台 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程
名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}]
[%-5level] [%thread] [%logger]
[%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:
TRACE、DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别
的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通
过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别,可也是包名或全类
名。 -->
<logger name="com.lzw.mapper" level="DEBUG"
/>
</configuration>
2.4 工具类抽取(简化代码)
public class SqlSessionUtil {
public static SqlSessionFactory
sqlSessionFactory=null;
static {
try {
//读取核心配置文件
InputStream in =
Resources.getResourceAsStream("mybatis-config.xml");
//构建SqlSessionFactory工厂对象
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession openSession(){
//通过SqlSessionFactory工厂对象获取
SqlSession对象(就是connection)
SqlSession sqlSession =
sqlSessionFactory.openSession();
return sqlSession;
}
}
使用工具类通过类名调用
@Test
public void test02() throws IOException {
//获取SqlSession
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//处理结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
2.5 增删改查
Mapper接口
//接口只规定方法,参数和返回值!映射配置文件中编写具体SQL
语句!
public interface EmployeeMapper {
//查询所有数据
public List<Employee> findAll();
//查询单个数据
public Employee findEmpById(Integer empId);
//添加一条数据
public Integer insertEmp(Employee employee);
//修改一条数据
public Integer updateEmp(Employee employee);
//删除一条数据
public Integer deleteEmpById(Integer empId);
}
映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<!--namespace:名称空间 该映射配置文件和哪个Mapper接口
进行映射绑定-->
<mapper
namespace="com.ll.mapper.EmployeeMapper">
<!--
id:唯一标识,映射接口的方法
resultType:输出的参数类型
-->
<select id="findAll"
resultType="com.ll.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
</select>
<select id="findEmpById"
resultType="com.ll.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
where emp_id = #{empId}
</select>
<insert id="insertEmp"
parameterType="com.ll.pojo.Employee">
insert into t_emp values(null,#{empName},#{empSalary})
</insert>
<update id="updateEmp"
parameterType="com.ll.pojo.Employee">
update t_emp set emp_name = #
{empName},emp_salary = #{empSalary} where emp_id = #{empId}
</update>
<delete id="deleteEmpById"
parameterType="java.lang.Integer">
delete from t_emp where emp_id = #{empId}
</delete>
</mapper>
测试
public class DemoTest {
//入门案例
@Test
public void test01() throws IOException {
//读取核心配置文件
InputStream in =
Resources.getResourceAsStream("mybatis-config.xml");
//构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(in);
//通过SqlSessionFactory工厂对象获取
SqlSession对象(就是connection)
SqlSession sqlSession =
sqlSessionFactory.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//处理结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
@Test
public void testSelectOne(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee =
employeeMapper.findEmpById(1);
//输出结果
System.out.println(employee);
//释放资源
sqlSession.close();
}
@Test
public void testInsert(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"王五",555.22);
Integer row =
employeeMapper.insertEmp(employee);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
@Test
public void testUpdate(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new
Employee(1,"zs",333.22);
Integer row =
employeeMapper.updateEmp(employee);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
@Test
public void testDelete(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer row =
employeeMapper.deleteEmpById(3);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
}
注意事项
三. MyBatis核心配置文件
MyBatis 的核心配置文件包含了会深深影响 MyBatis 行为的
设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
注意事项:在配置时按照以上顺序进行配置
3.1 properties(属性)
实际开发中,习惯将数据源的配置信息单独抽取成一个
properties文件,该标签可以加载额外配置的properties文
件。
数据库配置文件:db.properties
mybatis-config.xml文件
<configuration>
<!--加载外部properties-->
<properties resource="db.properties">
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
</transactionManager>
<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="EmployeeMapper.xml">
</mapper>
</mappers>
</configuration>
3.2 settings(设置)
EmployeeMapper.xml文件,在这里主要写的就是sql语句
<!--开启驼峰映射-->
<settings>
<setting name="mapUnderscoreToCamelCase"
value="true"/>
</settings>
<select id="findAll"
resultType="com.lzw.pojo.Employee">
select emp_id,emp_name,emp_salary from t_emp
</select>
3.3 typeAliases(类型别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML
配置,意在降低冗余的全限定类名书写
<!--类型别名-->
<typeAliases>
<!--单个指定-->
<!--<typeAlias type="com.lzw.pojo.Employee"
alias="Employee"></typeAlias>-->
<!--批量指定:直接将整个包下所有的类的类名作为别名
(且不区分到小写)-->
<package name="com.lzw.pojo"/>
</typeAliases>
<select id="findAll" resultType="Employee">
select emp_id,emp_name,emp_salary from t_emp
</select>
Mybatis 内部给常用的数据类型设定了很多别名。 以 int 类型
为例,可以写的名称有:int、integer、Integer、
java.lang.Integer、Int、INT、INTEGER 等等。
3.4 environments(环境配置)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL
映射应用于多种数据库之中, 现实情况下有多种理由需要这
么做。例如,开发、测试和生产环境需要有不同的配置。
不过要记住:尽管可以配置多个环境,但每个
SqlSessionFactory 实例只能选择一种环境
<!--开发环境-->
<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:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
<!--测试环境-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
四.数据输入
简单类型:只包含一个值的数据类型
基本数据类型:int、byte、short、double、……
基本数据类型的包装类型:Integer、Character、Double、……
字符串类型:String
复杂类型:包含多个值的数据类型
实体类类型:Employee、Department、……
集合类型:List、Set、Map、……
数组类型:int[]、String[]、……
复合类型:List<Employee>、实体类中包含集合…...
4.1 参数占位符
${} :拼接SQL。底层使用的是 Statement,往往这种情况会存在SQL注入问题
接口类
EmployeeMapper.xml文件
测试类输出的结果
#{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设
置参数值。从案例可以看出使用#{} 底层使用的是
PreparedStatement。
接口类:
EmployeeMapper.xml文件
测试类结果
总结:实际开发中,能用#{}实现的,肯定不用${}。
4.2 parameterType使用
对于有参数的mapper接口方法,我们在映射配置文件中应该
配置 ParameterType 来指定参数类型。只不过该属性都可以
省略。
<insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#{empSalary})
</insert>
4.3 单个简单类型参数
4.3.1 编写接口方法
public interface EmployeeMapper {
//删除一条数据
public Integer deleteEmpById(Integer empId);
}
4.3.2 编写SQL语句
<delete id="deleteEmpById"
parameterType="java.lang.Integer">
delete from t_emp where emp_id = #{empId}
</delete>
增删改接口的返回值是Integer,表示返回影响的行数,在映
射配置文件中不需要设置resultType
单个简单类型参数,在#{}中可以随意命名,但是没有必
要。通常还是使用和接口方法参数同名.
4.3.3 编写测试方法
@Test
public void testDelete(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer row =
employeeMapper.deleteEmpById(3);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
4.4 实体类类型参数
将多个参数封装成一个 实体对象 ,将该实体对象作为接口的
方法参数。该方式要求在映射配置文件的SQL中使用 #{内容}
时,里面的内容必须和实体类属性名保持一致。
4.4.1 编写接口方法
public interface EmployeeMapper {
//添加一条数据
public Integer insertEmp(Employee employee);
}
4.4.2 编写SQL语句
<!--实体传参,在映射配置文件中取值,直接写对象的属性名-->
<insert id="insertEmp" parameterType="Employee">
insert into t_emp values(null,#{empName},#{empSalary})
</insert>
4.4.3 编写测试方法
@Test
public void testInsert(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"王五",555.22);
Integer row =
employeeMapper.insertEmp(employee);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
4.5 零散的简单类型数据
零散的多个简单类型参数,如果没有特殊处理,那么Mybatis
无法识别自定义名称:
4.5.1 编写接口方法
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer updateNameById(StringempName,Integer empId);
}
4.5.2 编写SQL语句
<update id="updateNameById">
update t_emp set emp_name = #{empName} whereemp_id = #{empId}
</update>
4.5.3 编写测试方法
@Test
public void testupdateNameById(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer row =
employeeMapper.updateNameById("zs",1);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
会报错
4.5.4 解决方案
1.修改配置文件取值方式
<update id="updateNameById">
update t_emp set emp_name = #{param1} whereemp_id = #{param2}
</update>
2.使用 @Param("参数名称") 标记每一个参数,在映射配置
文件中就需要使用 #{参数名称} 进行占位
public interface EmployeeMapper {
//根据ID修改员工姓名
public Integer updateNameById(@Param("empName")
String empName,@Param("empId") Integer empId);
}
<update id="updateNameById">
update t_emp set emp_name = #{empName} whereemp_id = #{empId}
</update>
4.6 Map类型参数
将多个参数封装到map集合中,将map集合作为接口的方法
参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,
里面的内容必须和map集合中键的名称一致
4.6.1 编写接口方法
public interface EmployeeMapper {
//修改一条数据
public Integer updateEmp(Map<String,Object>map);
}
4.6.2编写sql语句
<!--通过key获取value的值-->
<update id="updateEmp" parameterType="Employee">
update t_emp set emp_name = #{empName},emp_salary = #{empSalary} where emp_id = #{empId}
</update>
4.6.3编写测试类
@Test
public void testUpdate(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String,Object> map=new HashMap<>();
map.put("empId",3);
map.put("empName","ww");
map.put("empSalary",55.33);
Integer row = employeeMapper.updateEmp(map);
//输出结果
System.out.println(row);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
五.数据输出
5.1 输出概述
数据输出总体上有两种形式:
增删改操作返回受影响行数:直接在接口方法中使用 int
或 long 类型接收即可
查询操作的查询结果
我们需要做的是,指定查询的输出数据类型即可!
并且插入场景下,实现主键数据回显示!
resultType = "全限定符 | 别名 | 如果是返回集合类型,写
范型类型即可"
5.2 返回单个简单类型
5.2.1 编写接口方法
public interface EmployeeMapper {
//查询总条数
public Integer findTotalCount();
}
5.2.2 编写SQL语句
<select id="findTotalCount" resultType="int">
select count(*) from t_emp
</select>
测试类
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Integer totalCount =
employeeMapper.findTotalCount();
//输出结果
System.out.println(totalCount);
//释放资源
sqlSession.close();
}
5.3返回实体类对象
5.3.1编写接口类
public interface EmployeeMapper {
//根据ID查询用户信息
public Employee findEmpById(Integer empId);
}
5.3.2编写sql语句
<select id="findEmpById" parameterType="int"
resultType="Employee">
select * from t_emp where emp_id = #{empId}
</select>
5.3.3编写测试类
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee =
employeeMapper.findEmpById(1);
//输出结果
System.out.println(employee);
//释放资源
sqlSession.close();
}
5.4 返回List类型
查询结果返回多个实体类对象,希望把多个实体类对象放在
List集合中返回。此时不需要任何特殊处理,在resultType属
性中还是设置实体类类型即可。
5.4.1 编写接口方法
public interface EmployeeMapper {
//查询所有数据
public List<Employee> findAll();
}
5.4.2 编写SQL语句
<select id="findAll" resultType="Employee">
select * from t_emp
</select>
5.4.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Employee> employeeList =
employeeMapper.findAll();
//输出结果
for (Employee employee : employeeList) {
System.out.println(employee);
}
//释放资源
sqlSession.close();
}
5.5 返回Map类型
适用于SQL查询返回的各个字段综合起来并不和任何一个现有
的实体类对应,没法封装到实体类对象中。
5.5.1 编写接口方法
public interface EmployeeMapper {
//查询所有员工的最高工资,最低工资,平均工资
public Map<String,Object> findSalary();
}
5.5.2 编写SQL语句
<select id="findSalary" resultType="Map">
select
max(emp_salary) 最高工资,
min(emp_salary) 最低工资,
avg(emp_salary) 平局工资
from t_emp
</select>
5.5.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String, Object> map =
employeeMapper.findSalary();
//输出结果
Set<Map.Entry<String, Object>> entrySet = map.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
System.out.println(entry.getKey()+"..."+entry.getValue());
}
//释放资源
sqlSession.close();
}
5.6 主键回填
5.6.1 自增长类型主键
接口类
public interface EmployeeMapper {
//添加数据
public Integer insertEmp(Employee employee);
}
编写sql语句
<!--
主键回填:当Mybatis执行新增后,会将数据库中该
条数据新增后的主键回填到实体的属性上
useGeneratedKeys:是否启用主键回填
keyProperty:指定主键回填到实体的哪个属性上
keyColumn:指定数据库中哪一列是主键(可选)
-->
<insert id="insertEmp" parameterType="Employee"
useGeneratedKeys="true" keyProperty="empId">
insert into t_emp values(null,#{empName},#{empSalary})
</insert>
编写测试类
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Employee employee=new Employee(null,"赵六",11.22);
Integer integer =
employeeMapper.insertEmp(employee);
//输出结果
System.out.println(integer);
//后续需要完善员工信息
System.out.println(employee);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
5.6.2 非自增长类型主键
而对于不支持自增型主键的数据库或者字符串类型主键,则可
以使用 selectKey 子元素:selectKey 元素将会首先运行,id
会被设置,然后插入语句会被调用!
使用 selectKey 帮助插入UUID作为字符串类型主键示例:
数据库表:
CREATE TABLE t_user (
id varchar(64) primary key,
username varchar(50),
password varchar(50)
)
编写接口类:
public interface UserMapper {
//添加数据
public Integer insertUser(User user);
}
编写sql语句
<mapper namespace="com.lzw.mapper.UserMapper">
<insert id="insertUser"
parameterType="user">
<!--
keyProperty:设置为实体的哪个属性,
resultType:设置返回值类型,
order:值为after和before
after: sql之后执行,before: sql之前执行
-->
<selectKey order="BEFORE" resultType="string" keyProperty="id">
select replace(UUID(),'-','')
</selectKey>
insert into t_user values(#{id},#{username},#{password})
</insert>
</mapper>
编写测试类
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
UserMapper userMapper =
sqlSession.getMapper(UserMapper.class);
//通过多态调用方法
//String id=
UUID.randomUUID().toString().replace("-","");
•
User user=new User(null,"zs","123456");
Integer integer =
userMapper.insertUser(user);
//输出结果
System.out.println(integer);
•
//后续需要完善用户信息
System.out.println(user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
5.7 属性和字段的映射
5.7.1 别名映射
将数据库表的字段别名设置成和实体类属性一致。
映射配置文件:
<!-- 给每一个字段设置一个别名,让别名和Java实体类中
属性名一致 -->
<select id="findAll" resultType="com.lzw.pojo.Employee">
select emp_id empId,emp_name
empName,emp_salary empSalary from t_emp
</select>
5.7.2 全局配置自动识别驼峰式命名规则
在Mybatis全局配置文件加入如下配置
<!-- 使用settings对Mybatis全局进行设置 -->
<settings>
<!-- 将xxx_xxx这样的列名自动映射到xxXxx这样驼峰式命名的属性名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
SQL语句中可以不使用别名
<select id="findAll" resultType="Employee">
select emp_id,emp_name,emp_salary from t_emp
</select>
5.7.3 使用resultMap
使用resultMap标签定义对应关系,然后引用这个对应关系
编写接口类
public interface UserMapper {
//根据员工ID查询员工信息
public Employee findEmpById(Integer empId);
}
<!--
使用resultMap标签进行数据的封装
id属性:当前resultMap的唯一标识
type属性:最终稿封装的类型,一般写全限定名
-->
<resultMap id="empResultMap"
type="Employee">
<!--id标签维护主键列,property写Java实体的属
性名,column写数据库表的字段名-->
<id property="empId" column="emp_id">
</id>
<!--result标签维护普通列,property写Java实体
的属性名,column写数据库表的字段名-->
<result property="empName"
column="emp_name"></result>
<result property="empSalary"
column="emp_salary"></result>
</resultMap>
<!--resultMap="empResultMap" 引用上面的
resultMap-->
<select id="findEmpById"
resultMap="empResultMap">
select * from t_emp where emp_id = #{empId}
</select>
编写测试类:
@Test
public void testFindById() throws
IOException {
SqlSession sqlSession =
SqlSessionUtil.openSession();
//4.获取接口的实现类对象
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//5.基于多态调用方法
Employee employee =
employeeMapper.findEmpById(1);
//6.释放资源
sqlSession.close();
//7.打印
System.out.println(employee);
}
六.MyBatis多表映射
6.1 数据准备
数据库表:
表与表之间的关系:一对一、一对多、多对多
表 一:
CREATE TABLE t_customer(
customer_id INT NOT NULL AUTO_INCREMENT,
customer_name CHAR(100),
PRIMARY KEY (customer_id)
);
CREATE TABLE t_order (
order_id INT NOT NULL AUTO_INCREMENT,
order_name CHAR(100),
customer_id INT,
PRIMARY KEY (order_id)
);
INSERT INTO t_customer (customer_name) VALUES
('张三');
INSERT INTO t_order (order_name, customer_id)
VALUES ('101', '1');
INSERT INTO t_order (order_name, customer_id)
VALUES ('102', '1');
INSERT INTO t_order (order_name, customer_id)
VALUES ('103', '1');
表二:
-- 创建讲师表
CREATE TABLE t_teacher (
t_id INT PRIMARY KEY,
t_name VARCHAR(50)
);
-- 创建学生表
CREATE TABLE t_student (
s_id INT PRIMARY KEY,
s_name VARCHAR(50)
);
-- 创建中间表
CREATE TABLE t_inner (
t_id INT,
s_id INT,
PRIMARY KEY (t_id, s_id)
);
-- 向讲师表中插入测试数据
INSERT INTO t_teacher VALUES (1, '张三');
INSERT INTO t_teacher VALUES (2, '李四');
INSERT INTO t_teacher VALUES (3, '王五');
-- 向学生表中插入测试数据
INSERT INTO t_student VALUES (1, '小明');
INSERT INTO t_student VALUES (2, '小红');
INSERT INTO t_student VALUES (3, '小刚');
-- 向中间表中插入测试数据
INSERT INTO t_inner VALUES (1, 1);
INSERT INTO t_inner VALUES (1, 3);
INSERT INTO t_inner VALUES (2, 2);
INSERT INTO t_inner VALUES (3, 1);
INSERT INTO t_inner VALUES (3, 3);
6.2 一对一查询
6.2.1 一对一查询的模型和SQL语句
用户表和订单表的关系为,一个用户有多个订单,一个订单只
从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所
属的用户
一对一查询的语句:
select
o.order_id,o.order_name,c.customer_id,c.customer
_name
from t_order o,t_customer c
where o.customer_id=c.customer_id
and o.order_id=1
6.2.2 创建Customer和Order实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private Integer customerId;
private String customerName;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Integer orderId;
private String orderName;
//代表当前订单从属于哪一个客户
private Customer customer;
}
6.2.3 创建OrderMapper接口
public interface OrderMapper {
public Order findOrderById(Integer orderId);
}
6.2.4 配置OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lzw.mapper.OrderMapper">
<resultMap id="oderAndCustomerMap" type="Order">
<id property="orderId"
column="order_id"></id>
<result property="orderName"
column="order_name"></result>
<!--
association标签维护一对一的关系
property属性:最终要封装的对象中的属性名
javaType属性:该属性的类型,可以是类的全限
定名或者别名
-->
<association property="customer" javaType="Customer">
<id property="customerId" column="customer_id"></id>
<result property="customerName" column="customer_name"></result>
</association>
</resultMap>
<!--resultType:是自动封装,且只能封装一个对象-->
<select id="findOrderById" resultMap="oderAndCustomerMap">
select o.order_id,o.order_name,c.customer_id,c.customer_name
from t_order o,t_customer c
where o.customer_id=c.customer_id
and o.order_id= #{orderId}
</select>
</mapper>
6.2.5 测试结果
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
OrderMapper orderMapper =
sqlSession.getMapper(OrderMapper.class);
//通过多态调用方法
Order order =
orderMapper.findOrderById(1);
//输出结果
System.out.println(order);
//释放资源
sqlSession.close();
}
6.3 一对多查询
6.3.1 一对多查询的模型和SQL语句
用户表和订单表的关系为,一个用户有多个订单,一个订单只
从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具
有的订单
一对多查询语句:
select
c.customer_id,c.customer_name,o.order_id,o.order
_name
from t_customer c,t_order o
where c.customer_id = o.customer_id
and c.customer_id = 1
6.3.2 创建Customer和Order实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private Integer customerId;
private String customerName;
//表示当前用户有哪些订单
public List<Order> orderList;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Integer orderId;
private String orderName;
//代表当前订单从属于哪一个客户
private Customer customer;
}
6.3.3 创建CustomerMapper接口
public interface CustomerMapper {
public Customer findCustomerById(Integer customerId);
}
6.3.4 配置CustomerMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.lzw.mapper.CustomerMapper">
<resultMap id="customerAndOrderMap"type="Customer">
<id property="customerId" column="customer_id"></id>
<result property="customerName" column="customer_name"></result>
<!--
collection标签:映射一对多的关联关系
property属性:实体类对象的属性名
ofType属性:集合属性中元素的类型
-->
<collection property="orderList" ofType="Order">
<id property="orderId" column="order_id"></id>
<result property="orderName" column="order_name"></result>
</collection>
</resultMap>
<select id="findCustomerById" parameterType="int" resultMap="customerAndOrderMap">
select
c.customer_id,c.customer_name,o.order_id,o.order_name
from t_customer c,t_order o
where c.customer_id = o.customer_id
and c.customer_id = #{customerId}
</select>
</mapper>
6.3.5 测试结果
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
CustomerMapper customerMapper =
sqlSession.getMapper(CustomerMapper.class);
//通过多态调用方法
Customer customer =
customerMapper.findCustomerById(1);
//输出结果
System.out.println(customer);
//释放资源
sqlSession.close();
}
6.4 多对多查询
6.4.1 多对多查询的模型和SQL语句
学生表和老师表的关系为,一个老师教过多个学生,一个学生
被多个老师教过
多对多查询的需求:查询老师同时查询出该老师教过哪些学生
Teacher:sql语句
select t.t_id,t.t_name,s.s_id,s_name
from t_teacher t,t_inner i,t_student s
where t.t_id=i.t_id and i.s_id=s.s_id and t.t_id
=1
Student:sql语句:
select s.s_id,s_name,t.t_id,t.t_name
from t_student s,t_inner i,t_teacher t
where s.s_id=i.s_id and i.t_id=t.t_id and s.s_id
=1
6.4.2 创建Teacher和Student实体
//Teacher实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
private Integer tId;
private String tName;
//表示一个老师教过多个学生
private List<Student> studentList;
}
//Student实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer sId;
private String sName;
//表示一个学生被多个老师教过
private List<Teacher> teacherList;
}
6.4.3 创建TeacherMapper和StudentMapper接口
StudentMapper接口
public interface StudentMapper {
//根据ID查询学生信息
public Student findStudentById(Integer sId);
}
TeacherMapper接口
public interface TeacherMapper {
//根据ID查询老师信息
public Teacher findTeacherById(Integer tId);
}
6.4.4 配置TeacherMapper.xml和StudentMapper.xm
TeacherMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<mapper namespace="com.lzw.mapper.TeacherMapper">
<resultMap id="teacherResultMap" type="Teacher">
<id property="tId" column="t_id"></id>
<result property="tName" column="t_name">
</result>
<collection property="studentList" ofType="Student">
<id property="sId" column="s_id"></id>
<result property="sName" column="s_name"></result>
</collection>
</resultMap>
<select id="findTeacherById" parameterType="int" resultMap="teacherResultMap">
select t.t_id,t.t_name,s.s_id,s_name
from t_teacher t,t_inner i,t_student s
where t.t_id=i.t_id and i.s_id=s.s_id and
t.t_id =#{tId}
</select>
</mapper>
StudentMapper.xm
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<mapper
namespace="com.lzw.mapper.StudentMapper">
<resultMap id="studentResultMap" type="Student">
<id property="sId" column="s_id"></id>
<result property="sName" column="s_name">
</result>
<collection property="teacherList" ofType="Teacher">
<id property="tId" column="t_id"></id>
<result property="tName" column="t_name"></result>
</collection>
</resultMap>
<select id="findStudentById" parameterType="int" resultMap="studentResultMap">
select s.s_id,s_name,t.t_id,t.t_name
from t_student s,t_inner i,t_teacher t
where s.s_id=i.s_id and i.t_id=t.t_id and
s.s_id =#{sId}
</select>
</mapper>
测试结果:
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
TeacherMapper teacherMapper =
sqlSession.getMapper(TeacherMapper.class);
StudentMapper studentMapper =
sqlSession.getMapper(StudentMapper.class);
//通过多态调用方法
Teacher teacher =
teacherMapper.findTeacherById(1);
Student student =
studentMapper.findStudentById(1);
//输出结果
System.out.println(teacher);
System.out.println(student);
//释放资源
sqlSession.close();
}
七.MyBatis动态SQL
7.1 动态SQL需求和简介
经常遇到很多按照很多查询条件进行查询的情况,比如京东的
商品搜索等。其中经常出现很多条件不取值的情况,在后台应
该如何完成最终的SQL语句呢?
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC
或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语
句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还
要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以
彻底摆脱这种痛苦。
7.2 动态SQL之和标签
7.2.1 编写接口方法
public interface EmployeeMapper {
//根据条件查询用户信息
public List<Employee>
findByCondition(Map<String,Object> map);
}
7.2.2 编写映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lzw.mapper.EmployeeMapper">
<!--
if标签:判断这个SQL语句片段是否要加入整个SQL语
句
true加入整个SQL语句中
false不加入整个SQL语句中
where标签:判断是否追加where关键字,会自动去除
多余的 and or关键字
-->
<select id="findByCondition" resultType="Employee">
select * from t_emp
<where>
<if test="empName !=null">
emp_name = #{empName}
</if>
<if test="empSalary !=null">
and emp_salary = #{empSalary}
</if>
</where>
</select>
</mapper>
7.2.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
Map<String,Object> map=new HashMap<>();
//map.put("empName","张三");
//map.put("empSalary",200.33);
List<Employee> employeeList =
employeeMapper.findByCondition(map);
//输出结果
System.out.println(employeeList);
//释放资源
sqlSession.close();
}
7.2 动态SQL之标签
循环执行sql的拼接操作,例如:select * from user where id
in (1,2,5)。
7.2.1编写接口方法
public interface EmployeeMapper {
//根据ID(1,3,5)查询员工信息
public List<Employee>
findByList(List<Integer> ids);
}
7.2.2 编写映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-
mapper.dtd">
<mapper namespace="com.lzw.mapper.EmployeeMapper">
<!--
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的容器
1.无别名,则使用list set array
2.可以使用使用@Param注解明确声明变量的名
称
collection属性中按照@Param注解指定的
名称来引用传入的参数。
item:代表遍历集合的每个元素,生成的变量名
open,cloase:循环开始前的符号,循环结束后的符
号
-->
<select id="findByList" resultType="Employee">
select * from t_emp
where emp_id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>
7.2.3 编写测试代码
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
List<Integer> ids=new ArrayList<>();
Collections.addAll(ids,1,3,5);
List<Employee> employeeList =
employeeMapper.findByList(ids);
//输出结果
System.out.println(employeeList);
//释放资源
sqlSession.close();
}
7.3 SQL片段抽取
可将重复的 sql 提取出来,使用时用 include 引用即可,达到
sql 重用的目的
*抽取重复的SQL片段
<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="baseSql">
select * from t_emp
</sql>
引用已抽取的SQL片段
<!-- 使用include标签引用声明的SQL片段 -->
<include refid="baseSql"/>
八.MyBatis扩展
8.1 Mapper批量映射优化
*需求
Mapper 配置文件很多时,在全局配置文件中一个一个注册太
麻烦,希望有一个办法能够一劳永逸。
*配置方式
Mybatis 允许在指定 Mapper 映射文件时,只指定其所在的
包:
<!--映射配置文件 -->
<mappers>
<package name="com.lzw.mapper"/>
</mappers>
此时这个包下的所有 Mapper 配置文件将被自动加载、注
册,比较方便。
*资源创建要求
Mapper 接口和 Mapper 配置文件名称一致
Mapper 接口:EmployeeMapper.java
Mapper 配置文件:EmployeeMapper.xml
Mapper 配置文件放在 Mapper 接口所在的包内
可以将mapperxml文件放在mapper接口所在的
包!
可以在sources下创建mapper接口包一致的文件夹
结构存放mapperxml文件
编写成.class文件
8.2 分页插件PageHelper
8.2.1 PageHelper插件介绍
MyBatis 对插件进行了标准化的设计,并提供了一套可扩展的
插件机制。插件可以在用于语句执行过程中进行拦截,并允许
通过自定义处理程序来拦截和修改 SQL 语句、映射语句的结
果等。
PageHelper 是 MyBatis 中比较著名的分页插件,它提供了多
种分页方式(例如 MySQL 和 Oracle 分页方式),支持多种
数据库,并且使用非常简单。下面就介绍一下 PageHelper 的
使用方式。
8.2.2 PageHelper插件使用
pom.xml引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
mybatis-config.xml配置分页插件
<plugins>
<plugin
interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect"
value="mysql"/>
</plugin>
</plugins>
其中,com.github.pagehelper.PageInterceptor 是
PageHelper 插件的名称,dialect属性用于指定数据库类型
(支持多种数据库)
*分页插件使用
编写接口:
public interface EmployeeMapper {
//查询所有员工信息
public List<Employee> findAll();
}
编写映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper
3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.lzw.mapper.EmployeeMapper">
<select id="findAll" resultType="Employee">
select * from t_emp
</select>
</mapper>
编写测试类:
@Test
public void testDemo(){
//使用工具类获取SqlSession对象
SqlSession sqlSession =
SqlSessionUtil.openSession();
//基于接口获取实现类对象(代理对象)
EmployeeMapper employeeMapper =
sqlSession.getMapper(EmployeeMapper.class);
//通过多态调用方法
//开启分页查询,但是分页更丰富的功能并非来自于它
PageHelper.startPage(3,3);
List<Employee> employeeList = employeeMapper.findAll();
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList,3);
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页的数量:"+pageInfo.getPageSize());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("是否为第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否为最后一页"+pageInfo.isIsLastPage());
System.out.println("上一页:"+pageInfo.getPrePage());
System.out.println("下一页:"+pageInfo.getNextPage());
//导航条上页码的数量
System.out.println("导航页码数:"+pageInfo.getNavigatePages());
System.out.println("==================");
//导航条上具体的页码
int[] nums = pageInfo.getNavigatepageNums();
for (int num : nums) {
System.out.print(num+"\t");
}
System.out.println("");
//释放资源
sqlSession.close();
}
8.3 ORM介绍
8.3.1 ORM思维介绍
ORM(Object-Relational Mapping,对象-关系映射)是一种
将数据库和面向对象编程语言中的对象之间进行转换的技术。
它将对象和关系数据库的概念进行映射,通过一系列的操作将
对象关联到数据表中的一行或多行上。
让我们可以使用面向对象思维进行数据库操作!!
8.3.2 ORM 框架通常有半自动和全自动
两种方式
* 半自动 ORM 通常需要程序员手动编写 SQL 语句或者配置
文件,将实体类和数据表进行映射,还需要手动将查询的
结果集转换成实体对象。
*全自动 ORM 则是将实体类和数据表进行自动映射,使用
API 进行数据库操作时,ORM 框架会自动执行 SQL 语句并
将查询结果转换成实体对象,程序员无需再手动编写 SQL
语句和转换代码。
8.3.3 半自动和全自动 ORM 框架的区别
*映射方式:半自动 ORM 框架需要程序员手动指定实体类
和数据表之间的映射关系,通常使用 XML 文件或注解方式
来指定;全自动 ORM 框架则可以自动进行实体类和数据
表的映射,无需手动干预。
*查询方式:半自动 ORM 框架通常需要程序员手动编写
SQL 语句并将查询结果集转换成实体对象;全自动 ORM
框架可以自动组装 SQL 语句、执行查询操作,并将查询结
果转换成实体对象。
*性能:由于半自动 ORM 框架需要手动编写 SQL 语句,因
此程序员必须对 SQL 语句和数据库的底层知识有一定的了
解,才能编写高效的 SQL 语句;而全自动 ORM 框架通过
自动优化生成的 SQL 语句来提高性能,程序员无需进行优
化。
* 学习成本:半自动 ORM 框架需要程序员手动编写 SQL 语
句和映射配置,要求程序员具备较高的数据库和 SQL 知
识;全自动 ORM 框架可以自动生成 SQL 语句和映射配
置,程序员无需了解过多的数据库和 SQL 知识。
常见的半自动 ORM 框架包括 MyBatis 等;常见的全自动
ORM 框架包括 Hibernate、Spring Data JPA、MyBatis-
Plus 等
8.4 逆向工程
8.4.1 逆向工程介绍
MyBatis 的逆向工程是一种自动化生成持久层代码和映射文件
的工具,它可以根据数据库表结构和设置的参数生成对应的实
体类、Mapper.xml 文件、Mapper 接口等代码文件,简化了
开发者手动生成的过程。逆向工程使开发者可以快速地构建起
DAO 层,并快速上手进行业务开发。
MyBatis 的逆向工程有两种方式:通过 MyBatis Generator
插件实现和通过 Maven 插件实现。无论是哪种方式,逆向工
程一般需要指定一些配置参数,例如数据库连接 URL、用户
名、密码、要生成的表名、生成的文件路径等等。
总的来说,MyBatis 的逆向工程为程序员提供了一种方便快捷
的方式,能够快速地生成持久层代码和映射文件,是半自动
ORM 思维像全自动发展的过程,提高程序员的开发效率
注意:逆向工程只能生成单表crud的操作,多表查询依然需
要我们自己编写!
8.4.2 逆向工程插件MyBatisX使用
MyBatisX 是一个 MyBatis 的代码生成插件,可以通过简单的
配置和操作快速生成 MyBatis Mapper、pojo 类和
Mapper.xml 文件。下面是使用 MyBatisX 插件实现逆向工程
*的步骤:
安装插件:
在 IntelliJ IDEA 中打开插件市场,搜索 MyBatisX 并安装。
*使用 IntelliJ IDEA连接数据库
8.5 注解开发
使用注解开发会比配置文件开发更加方便。如下就是使用注解
进行开发
public interface EmployeeMapper {
@Select("select * from t_emp where emp_id = #{empId}")
public Employee findEmpById(Integer EmpId);
//查询所有员工信息
public List<Employee> findAll();
}
注解是用来替换映射配置文件方式配置的,所以使用了注解,
就不需要再映射配置文件中书写对应的statement
Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见
名知意。如下:
* 查询 :@Select
* 添加 :@Insert
* 修改 :@Update
* 删除 :@Delete
注意:注解完成简单功能,配置文件完成复杂功能。
public interface EmployeeMapper {
//@Results注解相当于ResultMap
@Select("select * from t_emp where emp_id = #{empId}")
@Results(value={
@Result(id=true,column = "emp_id",property = "empId"),
@Result(column = "emp_name",property = "empName"),
@Result(column = "emp_salary",property = "empSalary")})
public Employee findEmpById(Integer EmpId);
//查询所有员工信息
public List<Employee> findAll();
}
8.6 设置模板