0%

MyBatis使用

  • MyBatis介绍与使用
  • MyBatis传统DAO模式开发

MyBatis介绍与使用

框架、ORM、MyBatis

原生JDBC实现CURD的问题

  1. 编码繁琐
  2. 需要我们自己将结果集映射成对象
  3. 性能不太好,连接池,缓存
  4. SQL语句和java代码的耦合度特别高
  5. … …

MyBatis 本是Apache的一个开源项目iBatis, 2010年这个项目由Apache Software Foundation 迁移到了Google Code,且改名为MyBatis 。2013年11月迁移到GitHub。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录

常用的基于JavaEE的三大开源框架,已经从SSH、SSH2过渡到了SSM:SpringMVC、Spring、MyBatis >>> springBoot

框架是一个半成品,已经对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的API可以省去很多代码编写,从而提高工作效率和开发速度

Mybatis是一持久层的款半自动的ORM映射框架

精简解释:MyBatis是一个半自动ORM框架,其本质是对JDBC的封装;使用MyBatis重点需要程序员编写SQL命令,不需要写一行JDBC代码

MyBatis使用

MyBatis官网说明文档

创建Maven项目导入依赖

  1. 使用maven导入jar文件
  2. 处理配置文件
  3. 开发业务代码

先创建一个空项目(Empty Project),项目名mybatisAll,用于存放后面Mybatis相关项目模块

如果不显示项目名,想显示项目名,可以close项目后,再次open即可

接下来设置maven,为我们自己安装的,不用idea自带的(当然用自带的也行)

File | Settings | Build, Execution, Deployment | Build Tools | Maven

Maven路径、配置文件、中央仓库设置好后,创建模块选择Maven项目,添加groupid(com.excepenxi)和aitifactid(mybatisTest01)

检查以下项目目录结构是否有缺失

在pom.xml中导入MyBatis相关依赖jar文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.excepenxi</groupId>
<artifactId>mybatisTest01</artifactId>
<version>1.0-SNAPSHOT</version>
<!--添加以下配置,找到对应软件包
1.打开官网 https://mvnrepository.com
2.搜素对应的包名(mysql-connector-java)
3.选择对应的版本,使用人数最多的包并拷贝配置
-->
<packaging>jar</packaging>
<dependencies>
<!--mysqlConnector-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--mybatis 核心jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--junit 单元测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!--lombok 编译用 简化get、set方法构造处理-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

File | Settings | Plugins | Marketplace搜索 MyBatisX 插件(小黑鸟图标)后安装并重启idea

File | Settings | Plugins | Marketplace搜索 lombok 插件后安装并重启idea

导入lombok依赖后,单独设置启用注解处理(每创建一个项目就要设置一次,仅对当前项目有效)

准备数据库、包结构和实体类、Mapper映射文件和核心配置文件

  • 数据库名:mydb
  • 字符集:utf8mb4
  • 表:4张表

dept(部门表),emp(员工表),salgrade(薪资等级表),bonus(奖金表)

包结构

  • mapper:连接数据库做增删改查的方法、接口、映射文件(使用MyBatis,dao用mapper代替)

    • 连接数据库四参数(driver、url、username、password)
  • pojo:存放与数据库表一一对应的实体类

  • resources:创建目录一层层创建,不可添加

  • test:存放开发测试代码

实体类Dept
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.excepenxi.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
// lombok注解,无需生成get set方法、构造器
@Data
// 全部参数的构造方法
@AllArgsConstructor
// 无参构造方法
@NoArgsConstructor
public class Dept implements Serializable {
// 以下三个属性和数据库对应表的列名保持一致,反射
private Integer deptno;
private String dname;
private String loc;
}
sqlMapConfig核心配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--加载mapper映射文件-->
<mappers>
<mapper resource="com/excepenxi/mapper/DeptMapper.xml"/>
</mappers>
</configuration>
DeptMapper映射文件
1
2
3
4
5
6
7
8
9
10
<?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="aaa">
<!--public List<Dept> findAll(){ }-->
<select id="findAll" resultType="com.excepenxi.pojo.Dept" >
select * from dept
</select>
</mapper>
Test1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.excepenxi.test;
import com.excepenxi.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
// 成员变量
private SqlSession sqlSession;
@Before
public void init(){
SqlSessionFactoryBuilder ssfb =new SqlSessionFactoryBuilder();
InputStream resourceAsStream = null;
try {
resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory factory=ssfb.build(resourceAsStream) ;
sqlSession=factory.openSession();
}
@Test
public void testFindAll() {
//System.out.println("test1");
// 调用SQL语句 根据id找到DeptMapper映射文件中的sql语句
List<Dept> list = sqlSession.selectList("findAll");
for (Dept dept : list) {
System.out.println(dept);
}
}
@After
public void release(){
// 关闭SQLSession
sqlSession.close();
}
}

运行结果

log4j1和log4j2的使用

log4j1

pom配置新增依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--日志的依赖 log4j-->
<!--log4j2
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.1</version>
</dependency>
-->
<!--log4j1-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

在resources下创建log4j.properties文件,以键值对方式存放

log4j1配置
1
2
3
4
5
6
7
8
9
10
11
12
#定义全局日志级别调试阶段推荐debug   error warn info debug
# 后面可添加 ,logfile 表示除控制台输出,也可以指定输出文件
log4j.rootLogger=debug,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/excepenxi.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

运行Test1

log4j2

pom.xml配置注释log4j1,取消log4j2配置;在resources下新增log4j2.xml配置文件;运行Test1测试

log4j2配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<!--控制台方式-->
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>
<!--滚动文件方式-->
<RollingFile name="RollingFile" filename="log/test.log"
filepattern="${logPath}/%d{YYYYMMddHHmmss}-fargo.log">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
</Appenders>
<!--控制打印方式-->
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console" />
<!--<AppenderRef ref="RollingFile" />-->
</Root>
</Loggers>
</Configuration>

核心配置文件中可以指定日志打印方式

1
2
3
4
5
6
7
8
<configuration>
+ <settings>
+ <!--指定mybatis日志方式,如果不指定,自动查找处理-->
+ <!--<setting name="logImpl" value="SLF4J"/>-->
+ <setting name="logImpl" value="LOG4J"/>
+ </settings>
...
</configuration>
关于事务配置

在mybatis核心配置文件中 envirment中,通过transactionManager配置事务的处理策略

  • JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围
  • MANAGED:这个配置几乎没做什么,它从来不提交或回滚一个连接,而它会让容器来管理事务的整个生命周期(比如 Spring 或 JEE 应用服务器的上下文) 默认情况下它会关闭连接。然而一些容器并不希望这样,因此如果你需要从连接中停止它,将closeConnection 属性设置为 false;mybatis本身并不做事务的处理,交给其他框架去处理事务,如spring
sqlMapConfig核心配置文件
1
2
3
4
5
6
7
8
9
10
<configuration>
...
<environments default="development">
<environment id="development">
+ <transactionManager type="JDBC"/>
- <transactionManager type="MANAGED"/>
...
</environment>
</environments>
</configuration>
关于映射文件加载方式
  1. mapper映射文件的文件路径导入 使用的mapper标签的resource属性
  2. 网络资源路径 使用的mapper标签的url属性
  3. 接口的全限定名导入 使用的是mapper标签的class属性 (基于接口的代理模式开发)
  4. 包扫描形式加载所有的mapper映射文件 使用的是 package标签
sqlMapConfig核心配置文件
1
2
3
4
5
6
7
8
9
<configuration>
...
<mappers>
+ <mapper resource="com/excepenxi/mapper/DeptMapper.xml"/>
- <mapper url="file:///xxx/DeptMapper.xml"
- <mapper class="com.excepenxi.mapper.DeptMapper"/>
- <package name="com.excepenxi.mapper"/>
</mappers>
</configuration>

关于实体类别名处理

在mybatis核心配置文件中使用别名处理

sqlMapConfig核心配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<configuration>
...
</settings>
+ <!--设置实体类别名-->
+ <typeAliases>
+ <!--
+ 通过包扫描给所有的实体类起别名;给指定报名下的所有类起别名
+ 默认每个实体类的别名是首字母小写的类名
+ Dept dept Emp emp
+ -->
- <typeAlias type="com.excepenxi.pojo.Dept" alias="dept"></typeAlias>
- <typeAlias type="com.excepenxi.pojo.Emp" alias="emp"></typeAlias>
+ <package name="com.excepenxi.pojo"/>
+ </typeAliases>
...
</configuration>

在映射文件的resultType 返回值类型 和paramterType 上就可以使用别名了

DeptMapper配置文件
1
2
3
4
5
6
-    <select id="findAll" resultType="com.excepenxi.pojo.Dept" >
<!--<select id="findAll" resultType="dept" parameterType="integer">-->
+ <select id="selectByEmpno" resultType="emp">
select * from emp where empno = 7566
</select>
</mapper>
MyBatis引入外部属性配置文件

关于外部属性配置文件存储数据库连接信息

在resources下创建jdbc.properties属性配置文件

1
2
3
4
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc_username=root
jdbc_password=root

在核心配置文件中引入db.properties属性文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="UTF-8" ?>
<!-- xml文档约束 约束xml文档中可以有哪些标签,哪些属性,以及标签的包含关系和顺序....
dtd 约束
schema 约束 -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
+ <properties resource="jdbc.properties"></properties>
<settings>
<!--设置日志处理方式-->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--设置实体类别名-->
<typeAliases>
<!--
通过包扫描给所有的实体类起别名;给指定报名下的所有类起别名
默认每个实体类的别名是首字母小写的类名
Dept dept Emp emp
-->
<package name="com.excepenxi.pojo"/>
</typeAliases>
<!--配置数据库链接信息-->
<environments default="development">
<!--数据源1-->
<environment id="development">
<transactionManager type="JDBC"/>
<!--一个数据源-->
<dataSource type="POOLED">
- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
- <property name="username" value="root"/>
- <property name="password" value="root"/>
+ <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>
<!--加载mapper映射文件-->
<mappers>
<mapper resource="com/excepenxi/mapper/DeptMapper.xml"/>
</mappers>
</configuration>

MyBatis传统DAO模式开发

普通模式,也称为传统DAO模式,就是在传统DAO模式下,定义接口和实现类,如 interface EmpDao class EmpDaoImpl implements EmpDao ;在实现类中,用SQLSession对象调用select insert delete update 等方法实现;目前极为少见,在传统模式下,我们需要知道SqlSession对象 实现CURD和 参数传递的处理

SqlSession查询的三种方式

SqlSession对象本身的API中就有三个查询方法,分别能够实现如下查询方式:

  1. 返回单个对象 selectOne
  2. 返回对象List集合 selectList
  3. 返回对象Map集合 selectMap

创建Emp实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.excepenxi.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Data
// 实现序列化接口
public class Emp implements Serializable {
// 实体类数据类型最好用包装类,不建议基本数据类型
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
}
准备Mapper映射文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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="EmpMapper">
<!--
1.返回单个对象
public Emp findOne();
id 相当于方法名
resultType 相当于返回值类型
sql语句的查询结果用哪个类来进行封装 如果返回值类型是集合,
这里写的也是集合中的元素对应的类,不是集合本身作为类型
paramaterType 参数类型
SQL语句就是具体的方法体的实现
-->
<select id="findOne" resultType="emp" >
select * from emp where empno = 7499
</select>
<!--
2.返回多个对象List集合
查询全部的员工信息
public List<Emp> findAll()
-->
<select id="findAll" resultType="emp">
select * from emp
</select>
<!--
3.返回多个对象的Map集合
把查询出来的数据中的某一列作为键,整条数据封装的对象作为值
public Map<key,Emp> findEmpMap()
<empno,Emp>
<key,Emp>
-->
<select id="findEmpMap" resultType="map">
select * from emp
</select>
</mapper>

sqlMapConfig中导入EmpMapper映射文件

sqlMapConfig核心配置文件
1
2
3
4
5
<!--加载mapper映射文件-->
<mappers>
<mapper resource="com/excepenxi/mapper/DeptMapper.xml"/>
+ <mapper resource="com/excepenxi/mapper/EmpMapper.xml"/>
</mappers>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.excepenxi.test;
import com.msb.pojo.Dept;
import com.msb.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Test2 {
private SqlSession sqlSession;
@Before
public void init(){
SqlSessionFactoryBuilder ssfb =new SqlSessionFactoryBuilder();
InputStream resourceAsStream = null;
try {
resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory factory=ssfb.build(resourceAsStream) ;
sqlSession=factory.openSession();
}
@Test
public void testSelectOne(){
// 查询单个对象
System.out.println("sqlSession查询单个对象");
Emp emp = sqlSession.selectOne("findOne");
System.out.println(emp);
}
@Test
public void testSelectList(){
// 查询多个对象的List集合
System.out.println("sqlSession查询对象List集合");
List<Emp> emps = sqlSession.selectList("EmpMapper.findAll");
emps.forEach(System.out::println);
}
@Test
public void testSelectMap(){
// 查询多个对象的Map集合
System.out.println("sqlSession查询对象Map集合");
Map<Integer, Emp> empMap = sqlSession.selectMap("findEmpMap", "EMPNO");
Set<Integer> empnos = empMap.keySet();
for (Integer empno : empnos) {
System.out.println(empno+" :" +empMap.get(empno));
}
}
@After
public void release(){
// 关闭SQLSession
sqlSession.close();
}
}

SqlSession传递参数的三种方式
  1. 单个基础数据类型作为参数
  2. 多个基础数据类型的map 集合作为参数
  3. 引用类型作为参数
SqlSession完成DML所有操作


----------- 本文结束 -----------




Buy me a coffee.