- MyBatis介绍与使用
- MyBatis传统DAO模式开发
MyBatis介绍与使用
框架、ORM、MyBatis
原生JDBC实现CURD的问题
- 编码繁琐
- 需要我们自己将结果集映射成对象
- 性能不太好,连接池,缓存
- SQL语句和java代码的耦合度特别高
- … …
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项目导入依赖
- 使用maven导入jar文件
- 处理配置文件
- 开发业务代码
先创建一个空项目(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>
<packaging>jar</packaging> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency> <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(奖金表)
实体类Dept1 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;
@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&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <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"> <select id="findAll" resultType="com.excepenxi.pojo.Dept" > select * from dept </select> </mapper>
|
Test11 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() { List<Dept> list = sqlSession.selectList("findAll"); for (Dept dept : list) { System.out.println(dept); } } @After public void release(){ sqlSession.close(); } }
|
log4j1和log4j2的使用
log4j1
pom配置新增依赖1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
<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
|
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
|
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" /> </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>
|
关于映射文件加载方式
- mapper映射文件的文件路径导入 使用的mapper标签的resource属性
- 网络资源路径 使用的mapper标签的url属性
- 接口的全限定名导入 使用的是mapper标签的class属性 (基于接口的代理模式开发)
- 包扫描形式加载所有的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&useUnicode=true&characterEncoding=UTF-8&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中就有三个查询方法,分别能够实现如下查询方式:
- 返回单个对象 selectOne
- 返回对象List集合 selectList
- 返回对象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">
<select id="findOne" resultType="emp" > select * from emp where empno = 7499 </select>
<select id="findAll" resultType="emp"> select * from emp </select>
<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(){ System.out.println("sqlSession查询对象List集合"); List<Emp> emps = sqlSession.selectList("EmpMapper.findAll"); emps.forEach(System.out::println); } @Test public void testSelectMap(){ 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.close(); } }
|
SqlSession传递参数的三种方式
- 单个基础数据类型作为参数
- 多个基础数据类型的map 集合作为参数
- 引用类型作为参数
SqlSession完成DML所有操作