MyBatis
一、MyBatis简介
1.1框架概念
框架:就是软件的半成品,完成了软件开发过程中的通用操作,只需要很少或者不用加工就能实现特定的功能,从而提高开发效率
1.2常用框架
- MVC框架:简化了Servlet的开发步骤
- Struts
- Struts2
SpringMVC
- 持久层框架:完成数据库操作的框架
- apache DBUtils
- Hibernate
- Spring JPA
MyBatis
- 胶水框架
Spring
SSM Spring SpringMVC MyBatis
SSH Spring Struts2 Hibernate
1.3MyBatis介绍
MyBatis是一个
半自动
的ORM
框架ORM(Object Relational Mapping)对象关系映射,将Java中的一个对象与数据表中一行记录一一对应
ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化
- MyBatis的前身是iBatis,iBatis是Apache软件基金会提供的开源项目
- 2010年iBatis迁移到Google code,正式更名为MyBatis
- 2013年迁移到Github托管
- MyBatis特点:
- 支持自定义SQL、存储过程
- 对原有的JDBC进行了封装,几乎消除了所有JDBC代码,让开发者只需关注SQL本身
- 支持XML和注解配置方式自动完成ORM操作,实现结果映射
二、MyBatis框架部署
框架部署,就是将框架引入到项目中
2.1 创建Maven项目
- Jva工程
- Web工程
2.2 在项目中添加MyBatis依赖
-
在pom.xml中添加依赖
- mybatis
- mysql driver
<dependencies> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> </dependencies>
2.3创建MyBatis配置文件
-
创建自定义模板
-
在
mybatis-config.xml
文件配置数据库连接信息<?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配置数据库连接信息 --> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager标签用于配置数据库管理方式 --> <transactionManager type="JDBC"></transactionManager> <dataSource type="PEELED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/le_tian_study?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>
三、MyBatis框架使用
案例:信息的数据库操作
3.1创建数据表
tb_students
create table tb_students( sid int primary key auto_increment, stu_num char(5) not null unique, stu_name VARCHAR(20) not null, stu_gender char(2) not null, stu_age int not null );
3.2创建实体类
Student.java
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data @AllArgsConstructor @NoArgsConstructor @ToString public class Student { private int sid; private String stuNum; private String stuName; private String stuGander; private int stuAge; }
3.3创建DAO接口,定义操作方法
StudentDAO.java
import com.le_tian.study.pojo.Student; public interface StudentDAO { //添加数据库信息 public int insertStudent(Student student); //删除数据库信息 public int deleteStudent(int stuNum); }
3.4创建DAO接口的映射文件
将
resources
文件定义为包
创建
mappers
文件夹并创建以实体类+Mapper
命名的xml文件
在映射文件中对DAO中定义的方法进行实现
<?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文件相当于DAO接口的“实现类”,namespace属性要指定‘实现’DAO接口的全限定名(包名) --> <mapper namespace="com.le_tian.study.dao.StudentDAO"> <!-- id要与接口的名称一致,parameterType定义参数类型,接口中实现可不写 --> <insert id="insertStudent" parameterType="com.le_tian.study.pojo.Student"> insert into tb_student(stu_num,sut_name,stu_gander,stu_age) values(#{stuNum},#{stuName},#{stuGander},#{stuAge}) </insert> <delete id="deleteStudent"> delete from tb_student where sut_name=#{stuNum} </delete> </mapper>
3.5将映射文件添加到主配置文件
<mappers> <mapper resource="mappers/StudentMapper.xml"></mapper> </mappers>
四、单元测试
在被测试类名后
ALT
+INSERT
选择Test
五、MyBatis的CRUD操作
5.1添加操作
package com.le_tian.study.dao; import com.le_tian.study.pojo.Student; 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.Test; import java.io.IOException; import java.io.InputStream; public class StudentDAOTest { @Test public void insertStudent() { try { //加载mybatis配置文件 InputStream resources = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //会话工厂 SqlSessionFactory factory = builder.build(resources); //会话(连接) SqlSession sqlSession = factory.openSession(); //通过会话获取DAO对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); //测试方法 int i = studentDAO.insertStudent(new Student(0,"1002", "张三", "男", 21)); sqlSession.commit(); System.out.println(i); } catch (IOException e) { e.printStackTrace(); } } }
<insert id="insertStudent" parameterType="com.le_tian.study.pojo.Student"> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values(#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
5.2删除操作
@Test public void deleteStudent() { try { //读取mybatis配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //SqlSessionFactory表示MyBatis的会话工厂 SqlSessionFactory factory = builder.build(is); //SqlSession表示MyBatis与数据库之间的会话,通过工厂方法设计模式 SqlSession sqlSession = factory.openSession(); //通过SqlSession对象调用getMapper方法获取DAO接口对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); int i = studentDAO.deleteStudent("1002"); sqlSession.commit(); System.out.println(i); } catch (IOException e) { e.printStackTrace(); } }
![]() |
---|
<delete id="deleteStudent"> delete from tb_students where stu_num=#{stuNum} </delete>
5.3修改操作
@Test public void updateStudent() { try { //读取mybatis配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //会话工厂 SqlSessionFactory build = builder.build(is); //创建会话(连接) SqlSession sqlSession = build.openSession(); //虚拟StudentDAO对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); //测试 int i = studentDAO.updateStudent(new Student(0, "1002", "李四", "女", 21)); //断言 asserEquals(1,i); sqlSession.commit(); System.out.println(i); } catch (IOException e) { e.printStackTrace(); } }
<update id="updateStudent"> update tb_students set stu_name=#{stuName},stu_gender=#{stuGender},stu_age=#{stuAge} where stu_num=#{stuNum} </update>
5.4查询操作
@Test public void selectStudent() { try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory build = builder.build(is); SqlSession sqlSession = build.openSession(); StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); Student student = studentDAO.selectStudent("1002"); assertNotNull(student); } catch (IOException e) { e.printStackTrace(); } }
<!-- resultType指定结果封装的对象类型 --> <!-- resultSets指定当前操作返回的集合类型(可省略) --> <!-- resultMap用于定义实体类与数据表的映射关系(ORM) --> <!-- resultMap用于一个实体的映射关系,当配置了resultMap之后 resultType就可以省略 --> <resultMap id="StudentMap" type="com.le_tian.study.pojo.Student"> <id column="stu_id" property="stuID"/> <result column="stu_num" property="stuNum"/> <result column="stu_name" property="stuName"/> <result column="stu_gender" property="stuGender"/> <result column="stu_age" property="stuAge"/> </resultMap> <select id="selectStudent" resultType="com.le_tian.study.pojo.Student" resultSets= resultMap="StudentMap"> select sid,stu_num stuNum,stu_name stuName,stu_gender stuGender,stu_age stuAge from tb_students </select>
5.5统计
@Test public void countStudent(){ try { InputStream resources = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(resources); SqlSession sqlSession = factory.openSession(); StudentDAO mapper = sqlSession.getMapper(StudentDAO.class); System.out.println(mapper.countStudent()); } catch (IOException e) { e.printStackTrace(); } }
<select id="countStudent" resultType="int"> select count(1) from tb_students </select>
5.6查询操作-多参数查询
在MyBatis进行操作
单个参数
- 操作方法只有一个简单类型或者字符串类型的参数,在Mapper配置中可以直接通过
#{str}
直接获取- 操作方法只有一个对象类型的参数,在Mapper配置中可以直接通过
#attrName
获取对象的指定属性值(attrName)必须是参数对象的属性- 操作方法有一个Map类型的参数,在Mapper配置中可以直接通过
#{key}
获取key对应的value
多个参数
- 在StudentDAO中定义操作方法,使用
@Param
注解声明参数的别名
//分页查询 public List<Student> selectStudentByPage(@Param("start") int start,@Param("page") int page);
在StudentMapper.xml配置sql时,使用
#{别名}
获取指定的参数
注意:
如果DAO操作方法没有通过@Param
指定参数别名,在SQL中有可以通过arg0,arg1,...
或者param1,param2,...
获取参数
<select id="selectStudentByPage" resultMap="StudentMap"> <!-- limit #{arg0},#{arg1} limit #{param1},#{param2} --> select sid,stu_num,stu_name,stu_gender,stu_age from tb_students limit #{start},#{page} </select>
5.8添加操作回填生成的主键
StduentMapper.xml的添加操作标签--insertt
<!-- useGeneratedKeys 设置添加操作是否需要回填生成的主键 --> <!-- keyProperty 设置回填的主键赋值到参数对象的某个属性 --> <insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuID"> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values(#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
@Test public void selectStudent() { try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory build = builder.build(is); SqlSession sqlSession = build.openSession(); StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); List<Student> student = studentDAO.selectStudent(); student.forEach(student1 -> System.out.println(student1.toString())); assertNotNull(student); } catch (IOException e) { e.printStackTrace(); } }
六、工具类的封装
package com.le_tian.study.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisUtil { public static SqlSessionFactory factory; public static final ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>(); static{ try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); factory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ SqlSession sqlSession = sqlSessionThreadLocal.get(); if(null==sqlSession){ sqlSession = factory.openSession(); sqlSessionThreadLocal.set(sqlSession); } return sqlSession; } public static <T extends Object>T getMapper(Class<T> c){ return getSqlSession().getMapper(c); } }
七、事务管理
SqlSession对象
- getMapper(DAO.class):获取Mapper(DAO接口实例)
- 事务管理
7.1手动提交事务
sqlSession.commit();
提交事务sqlSession.roolback();
事务回滚
@Test public void insertStudent() { SqlSession sqlSession = MyBatisUtil.getSqlSession(); try { //通过会话获取DAO对象 //当我们获取sqlSession对象时,就默认开启了事务 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); //测试StudentDAO中的方法 Student student = new Student(0, (Integer.parseInt(studentDAO.selectStudentMaxStuNum()) + 1) + "", "张六", "男", 21); int i = studentDAO.insertStudent(student); //操作完成之后,手动提交 sqlSession.commit(); }catch (Exception e){ //当操作出现异常,调用rollback进行回滚 sqlSession.rollback(); } }
7.2自动提交事务
通过SqlSessionFactory调用openSession方法获取SqlSession对象时,可以通过参数设置事务是否自动提交
- 自动提交事务:factory.openSession(true)
- 手动提交事务:factory.openSession();/factory.openSession(false)
MyBatisUtil优化
package com.le_tian.study.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisUtil { public static SqlSessionFactory factory; public static final ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>(); static{ try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); factory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return getSqlSession(false); } private static SqlSession getSqlSession(boolean isAutocommit){ SqlSession sqlSession = sqlSessionThreadLocal.get(); if(null==sqlSession){ sqlSession = factory.openSession(isAutocommit); sqlSessionThreadLocal.set(sqlSession); } return sqlSession; } public static <T extends Object>T getMapper(Class<T> c){ return getSqlSession(true).getMapper(c); } }
测试操作
@Test public void deleteStudent() { StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class); studentDAO.deleteStudent("1002"); }
八、MyBatis主配置文件
mybatis-config.xml是MyBatis框架的主配置文件,只要用于配置MyBatis数据源及属性信息
8.1properties标签
- 在resources目录下创建
jdbc.properties
文件,配置键值对如下:
jdbc.mysql.driver=com.mysql.jdbc.Driver jdbc.mysql.url=jdbc:mysql://localhost:3306/le_tian_study?useSSL=false&characterEncoding=UTF-8 jdbc.mysql.username=root jdbc.mysql.password=root
- 在
mybatis-config.xml
中通过properties
标签引用jdbc.properties
文件
<?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> <!-- properties标签:1.可以定义键值对 2.可以引用属性文件 --> <properties resource="jdbc.properties"/> <!-- 在environments配置数据库连接信息 --> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager标签用于配置数据库管理方式 --> <transactionManager type="JDBC"/> <!-- POOLED使用MyBatis内置的连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.mysql.driver}"/> <property name="url" value="${jdbc.mysql.url}"/> <property name="username" value="${jdbc.mysql.username}"/><property name="password" value="${jdbc.mysql.password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/StudentMapper.xml"/> </mappers> </configuration>
8.2setting标签
<!-- 设置mybatis的属性 --> <settings> <!-- 启动二级缓存 --> <setting name="cacheEnabled" value="true"/> <!-- 启动延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> </settings>
8.3typeAliases标签
<!-- typeAliases标签用于给实体类取别名,在映射文件中可以直接使用别名来替代实体类的全限定名 --> <typeAliases> <typeAlias type="com.le_tian.study.pojo.Student" alias="student"/> </typeAliases>
8.4plugins标签
<!-- plugins标签,用于配置MyBatis插件(分页插件) --> <plugins> <plugin interceptor=""></plugin> </plugins>
8.5environments标签
<!-- 在environments配置数据库连接信息 --> <!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 --> <!-- default属性,用来指定使用哪个environment标签 --> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager标签用于配置数据库管理方式 type="JDBC" 可以进行事务的提交和回滚操作 type="MANAGED" 依赖容器完成事务管理,本身不进行事务的提交和回滚操作 --> <transactionManager type="JDBC"/> <!-- dataSource标签用来配置数据库连接信息 POOLED|UNPOOLED --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.mysql.driver}"/> <property name="url" value="${jdbc.mysql.url}"/> <property name="username" value="${jdbc.mysql.username}"/><property name="password" value="${jdbc.mysql.password}"/> </dataSource> </environment> </environments>
8.6mappers标签
加载映射配置(映射文件、DAO注解)
<mappers> <mapper resource="mappers/StudentMapper.xml"/> </mappers>
九、映射文件
9.1MyBatis初始化
![]() |
---|
9.2mapper根标签
mapper文件相当于DAO接口的‘实现类’,namespace属性要指定
实现
DAO接口的全限定名
9.3insert标签
声明添加操作(sal:insert ...)
常用属性
id,绑定对应DAO接口中的方法
parameterType,用于指定接口中对应方法的参数类型(可省略)
useGeneratedKeys,设置添加操作是否需要回填生成的主键
keyPeoperty属性,指定回填的id设置到参数对象中的哪个属性
timeout,设置此操作的超时时间,不设置则一直等待
主键回填
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuID" timeout="3000"> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values(#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
<insert id="insertStudent"> <selectKey keyProperty="stuID" resultType="java.lang.Integer"> select last_insert_id() </selectKey> </insert>
9.4delete标签
声明删除操作
9.5update标签
声明修改操作
9.6select标签
声明查询操作
- id,指定绑定方法的方法名
- parameterType,设置参数类型
- resultType,指定当前sql返回数据封装的对象类型(实体类)
- resultMap,指定从数据表到实体类的字段和属性的对应关系
- useCache,定义查询操作是否需要缓存
- timeout,设置连接超时时间
9.7resultMap标签
<!-- resultMap用于定义实体类与数据表的映射关系(ORM) --> <resultMap id="StudentMap" type="student"> <id column="stu_id" property="stuID"/> <result column="stu_num" property="stuNum"/> <result column="stu_name" property="stuName"/> <result column="stu_gender" property="stuGender"/> <result column="stu_age" property="stuAge"/> </resultMap>
9.8cache标签
设置当前DAO进行数据库操作时的缓存属性设置
<cache type="" size=“” readOnly=""/>
9.9sql和include
SQL片段
<sql id="wanglaoji">sid,stu_num,stu_name,stu_gender,stu_age/> <select id="IistStudents" resultWap="studentMap"> select <include refid="wanglaoji"/> from tb_students </select>
10、分页插件
分页插件是一个独立于MyBatis框架之外的第三方插件
10.1添加分页插件的依赖
PageHelper
<!-- pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.0</version> </dependency>
10.2配置插件
在MyBatis的主配置文件
mybatis-config.xml
中通过plugins
标签进行配置
<!-- 分页插件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"></plugin> </plugins>
10.3分页查询
pagenum:分页页数 pageSize:分页条数 size:查询的信息条数 startRow:信息在数据库开始的行数 endRow:信息在数据库结束的行数 pages:当前页数 prePage:上一页的页数 nextPage:下一页的页数 isFirstpage:是不是第一页 isLastpage:是不是最后一页 list:查询结果
@Test public void selectStudent() { StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class); PageHelper.startPage(2,4); List<Student> student = studentDAO.selectStudent(); PageInfo<Student> pageInfo = new PageInfo<>(student); pageInfo.getList().forEach(student1 -> System.out.println(student1)); assertNotNull(student); }
十一、关联映射
11.1实体关系
实体--数据实体,实体关系指的就是数据与数据之间的关系
例如:用户和角色/房屋和楼栋/订单和商品
实体关系分为以下四种
一对一关联
实例:人和身份证/学生和学生证
数据表关系
-
主键关联(用户表主键和详情表主键相同时,表示匹配数据)
-
唯一外键关联
-
一对多关联/多对一关联
一对多:班级和学生/类别和商品
多对一:学生和班级/商品和类别
数据表关系:在多的一端添加外键和一的一端进行关联
-
多对多关联
用户和角色/角色和权限/房屋和业主
数据表关系:建立第三张关系表添加两个外键分别与两张表主键进行关联
11.2创建项目,部署MyBatis框架
-
创建web项目(maven)
<!-- javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- jsp-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> -
部署MyBatis框架
- 添加依赖
<!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <!-- mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> -
配置文件
-
帮助类
package com.mybatis.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisUtil { public static SqlSessionFactory factory; public static final ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>(); static{ try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); factory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return getSqlSession(false); } private static SqlSession getSqlSession(boolean isAutocommit){ SqlSession sqlSession = sqlSessionThreadLocal.get(); if(null==sqlSession){ sqlSession = factory.openSession(isAutocommit); sqlSessionThreadLocal.set(sqlSession); } return sqlSession; } public static <T extends Object>T getMapper(Class<T> c){ return getSqlSession(true).getMapper(c); } }
11.3一对一关联
实例:用户----详情
11.3.1创建数据表
-- 用户信息表 cteate table users( user_id int primary key auto_increament, user_name varchar(20) not null unique, user_pwd varchar(20) not null, user_realname varchar(20) not null, user_img varchar(100) not null ); -- 用户详情表 create table details( detail_id int primary key auto_incrment, user_addr varchar(50) not null, user_tel char(11) not null, user_desc varchar(200), uid int not null unique -- constraint FK_USER foreign key(uid) references users(user_id) )
11.3.2创建实体类
User.java
package com.mybatis.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data @ToString @NoArgsConstructor @AllArgsConstructor public class User { private int userID; private String userName; private String userPwd; private String userRealName; private String userImg; }
Detail.java
package com.mybatis.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data @ToString @NoArgsConstructor @AllArgsConstructor public class Detail { private int detailID; private String userAddress; private String userTel; private String userDesc; private int uid; }
11.3.3添加操作
11.3.4一对一关联查询
在查询用户的同时关联查询出与之对应的详情
实体
User | Detail |
---|---|
![]() |
![]() |
映射文件
-
连接查询
<resultMap id="UserMap" type="com.mybatis.pojo.User"> <id column="user_id" property="userID"/> <result column="user_name" property="userName"/> <result column="user_pwd" property="userPwd"/> <result column="user_realname" property="userRealName"/> <result column="user_img" property="userImg"/> <result column="detail_id" property="detail.detailID"/> <result column="user_addr" property="detail.userAddress"/> <result column="user_tel" property="detail.userTel"/> <result column="user_desc" property="detail.userDesc"/> <result column="uid" property="detail.uid"/> </resultMap> <select id="selectUserByName" resultMap="UserMap"> select user_id,user_name,user_img,detail_id,user_addr,user_tel,user_desc,uid from users inner join details on users.user_id=details.uid where users.user_name=#{userName} </select> -
子查询
<resultMap id="UserMap" type="com.mybatis.pojo.User"> <id column="user_id" property="userID"/> <result column="user_name" property="userName"/> <result column="user_pwd" property="userPwd"/> <result column="user_realname" property="userRealName"/> <result column="user_img" property="userImg"/> <association property="detail" select="com.mybatis.dao.DetailDAO.selectDetailByUid" column="user_id"/> </resultMap> <select id="selectUserByName" resultMap="UserMap"> select user_id,user_name,user_pwd,user_realname,user_img from users where user_name=#{userName} or user_realname=#{userName} </select>
11.4一对多关联
案例:班级----学生
11.4.1创建数据表
-- 创建班级信息表 create table classes( cid int primary key auto_increment, cname varchar(30) not null unique, cdesc varchar(100) ); -- 创建学生表 create table students( sid char(5) primary key, sname varchar(20) not null, sage int not null, scid int not null );
11.4.2创建实体类
Clazz.java
@Data @AllArgsConstructor @NoArgsConstructor @ToString public class Clazz { private Integer cId; private String cName; private String cDesc; private List<Student> stus;//存储班级下的所有学生 }
Student.java
@Data @AllArgsConstructor @NoArgsConstructor @ToString public class Student { private String sId; private String sName; private Integer sAge; private Integer cId; }
11.4.3关联查询
当查询一个班级的时候,要关联查询出这个班级下的所有学生
连接查询
<resultMap id="ClazzMap" type="Clazz"> <id column="cid" property="cId"/> <result column="cname" property="cName"/> <result column="cdesc" property="cDesc"/> <!-- Clazz对象的students是一个List集合,需要使用collection标签 --> <!-- collection标签的ofType属性声明集合中元素的类型 --> <collection property="students" ofType="Student"> <result column="sid" property="sId"/> <result column="sname" property="sName"/> <result column="sage" property="sAge"/> <result column="scid" property="sCid"/> </collection> </resultMap> <select id="selectClass" resultMap="ClazzMap"> select cid,cname,cdesc,sid,sname,sage,scid from classes c inner join students s on c.cid=s.scid where cid=#{classId} </select>
子查询
<resultMap id="ClazzMap" type="Clazz"> <id column="cid" property="cId"/> <result column="cname" property="cName"/> <result column="cdesc" property="cDesc"/> <!-- Clazz对象的students是一个List集合,需要使用collection标签 collection标签的ofType属性声明集合中元素的类型 --> <collection property="students" select="com.mybatis.dao.StudentDAO.selectStudentByCid" column="cid"/> </resultMap> <select id="selectClass" resultMap="ClazzMap"> select cid,cname,cdesc from classes c where cid=#{classId} </select>
11.5多对一关联
实例:学生----班级
11.5.1创建实体类
Student | Clazz |
---|
十二、动态SQL
根据筛选条件的不同,执行的SQL也不一样;可以通过穷举来一一完成不同条件的筛选,但是这种实现思路过于繁琐和复杂,MyBatis就提供了动态SQL的配置方式来实现多条件查询
12.1什么是动态SQL
根据查询条件动态完成SQL拼接
12.2动态SQL使用案例
12.2.1创建数据表
create table members( member_id int primary key auto_increment, member_nick varchar(20) not null unique, member_gander char(2) not null, member_age int not null, member_city varchar(30) not null );
12.2.2创建实体类
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class Member { private int memberId; private String memberNick; private String memberGander; private int memberAge; private String memberCity; }
十四、MyBatis日志配置
MyBatis作为一个封装好的ORM框架,其运行过程我们没办法跟踪,为了让开发者了解MyBatis执行流程及每个执行步骤所完成的工作,MyBatis框架本身支持log4j日志框架,对运行的过程进行跟踪记录。我们只需对MyBatis进行相关的日志配置,就可以看到MyBatis运行过程中的日志信息
14.1添加日志框架依赖
<!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
14.2添加日志配置文件
-
在resources目录下创建名为
log4j.properties
文件 -
在·
log4j.properties
文件配置日志输出方式# 声明日志的输出级别 输出方式 log4j.rootLogger=DEBUG,stdout # MyBatis logging configuration... log4j.logger.org.mybatis.example.Blogmapper=TRACE # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # 定义日志的打印格式 %t 表示现场名称 %5p 日志级别 %msg 日志信息 log4j.appender.stdout.layout.Conversionpattern=[%t] %5p - %n%m
14.3日志信息的级别
在使用日志框架输出日志信息的时候,会根据输出的日志信息的重要程度分为5个等级
级别 | 说明 |
---|---|
DEBUG | 调试信息 |
INFO | 提示信息 |
WARN | 警告性信息 |
ERROR | 一般性错误 |
FATAL | 致命性错误 |
十五、配置数据库连接池-整合Druid
MyBatis做为一个ORM框架,在进行数据库操作时是需要和数据库建立连接的,MyBatis支持基于数据库连接池的连接创建方式
当配置MyBatis数据源时,只要配置了
dataSource
标签的type属性值为POOLED
时,就可以使用MyBatis内置的连接池管理连接如果使用三方数据库连接池,则需要自定义配置
15.1常见的连接池
- DBCP
- C3P0
- Druid:性能比较好,提供了比较便携的监控系统
- HIkari:性能最好
功能 | dbcp | druid | c3p0 | tomcat-jdbc | HikariCP |
---|---|---|---|---|---|
是否支持PSCache | 是 | 是 | 是 | 否 | 否 |
监控 | jmx | jmx/log/http | jmx,log | jmx | jmx |
扩展性 | 弱 | 好 | 弱 | 弱 | 弱 |
sql拦截及解析 | 无 | 支持 | 无 | 无 | 无 |
代码 | 简单 | 中等 | 复杂 | 简单 | 简单 |
更新时间 | 2015.8.6 | 2015.10.10 | 2015.12.09 | 2015.12.3 | |
特点 | 依赖于common-pool | 阿里开源,功能全面 | 历史久远,代码逻辑复杂,且不易维护 | 优化力度大,功能简单,起源于boneCP | |
连接池管理 | LinkedBlockingDeque | 数组 | FairBlockingQueue | threadlocal+CopyOnWriteArrayList |
15.2添加Druid依赖
<!-- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.12</version> </dependency>
15.3创建Druid连接池工厂
public class DruidDataSourceFactory extends PooledDataSourceFactory { public DruidDataSourceFactory() { this.dataSource = new DruidDataSource(); } }
15.4将DruidDataSourceFactory配置给MyBatis数据源
<environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="com.le_tian.utils.DruidDataSourceFactory"> <property name="driverClass" value="${jdbc.mysql.driver}"/> <property name="jdbcUrl" value="${jdbc.mysql.url}"/> <property name="username" value="${jdbc.mysql.username}"/> <property name="password" value="${jdbc.mysql.password}"/> </dataSource> </environment> </environments>
十六、MyBatis缓存
MyBatis是基于JDBC的封装,使数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化:
- 在MyBatis引入了缓存机制,用于提升MyBatis的检索效率
- 在MyBatis引入延迟加载机制,用于减少对数据库不必要的访问
16.1缓存的工作原理
![]() |
---|
16.2MyBatis缓存
MyBatis缓存分为一级缓存和二级缓存
16.2.1一级缓存
一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配的缓存内存,无需手动开启可直接使用;多个SqlSession的缓存是不共享的
特性:
如果多次查询使用的是同一个SqlSeesion对象,则第一次查询之后数据会存放到缓存,后续的查询则优先查询缓存中存储的数据
如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致
再次查询时想要跳过缓存直接查询数据库,则可以通过
sqlSession.clearCaChe();
来清除当前SqlSession的缓存如果第一次查询之后第二次查询之前,使用当前的sqlSeesion执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库
16.2.2两次查询与数据库数据不一致问题
![]() |
---|
16.2.3二级缓存
二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的SqlSession可以共享二级缓存;在应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享
特性:
二级缓存默认没有开启,需要在
mybatis-config.xml
中的settings
标签开启二级缓存只能缓存实现序列化接口的对象
-
在
mybatis-config.xml
开启使用二级缓存<settings> <setting name="cacheEnabled" value="true"/> </settings> -
在需要使用二级缓存的Mapper文件中配置cache标签使用功能二级缓存
<cache/> -
被缓存的实体类序列化接口
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class Member implements Serializable { private int memberId; private String memberNick; private String memberGender; private int memberAge; private String memberCity; } -
测试
@Test public void testQueryMemberById(){ SqlSessionFactory factory = MyBatisUtil.getSqlSessionFactory(); //多个SqlSession对象必须来自同一个SqlSessionFactory SqlSession sqlSession1 = factory.openSession(true); SqlSession sqlSession2 = factory.openSession(true); MemberDAO memberDao1 = sqlSession1.getMapper(MemberDAO.class); Member member1 = memberDao1.queryMemberById(1); System.out.println(member1); //将当前sqlSession查询结果暂存到二级缓存需要执行commit(); sqlSession1.commit(); MemberDAO memberDAO2 = sqlSession2.getMapper(MemberDAO.class); Member member2 = memberDAO2.queryMemberById(1); System.out.println(member2); }
16.3查询操作的缓存开关
<select id="queryMemberById" resultMap="memberMap" useCache="false"> select member_id,member_nick,member_gender,member_age,member_city from members where member_id=#{mid} </select>
十七、延迟加载
延迟加载----如果在MyBatis开启了延迟加载,在执行了子查询(至少查询两次)时,默认只执行第一次查询,当用到子查询的查询结果时,才会触发子查询的执行;如果无需使用子查询的结果,则子查询不会执行
本文作者:Byron_Zora
本文链接:https://www.cnblogs.com/byzora/p/17336174.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步