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进行操作

单个参数

  1. 操作方法只有一个简单类型或者字符串类型的参数,在Mapper配置中可以直接通过#{str}直接获取
  2. 操作方法只有一个对象类型的参数,在Mapper配置中可以直接通过#attrName获取对象的指定属性值(attrName)必须是参数对象的属性
  3. 操作方法有一个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&amp;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 中国大陆许可协议进行许可。

posted @   Byron_Zora  阅读(19)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.