Mybatis的学习笔记

文章目录

Mybatis

一、Mybatis介绍

Mybatis是一个半自动的ORM框架

ORM(Object Relational Mapping)对象关系映射,将java中的一个对象与数据表中一行记录一一对应

ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化。

Mybatis的前身是iBatis。

Mybatis中文网:MyBatis中文网

Mybatis的特点

  • 支持自定义SQL、存储过程
  • 对原有的JDBC进行了封装,几乎消除了所有JDBC代码,让开发者只需关注SQL本身
  • 支持XML和注解配置方式自定义完成ORM操作,实现结果映射

二、Mybatis基本操作

1、添加Mybatis依赖
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
2、创建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下可以配置多个不同id的environment,不同环境用不同的设置development,test..-->
    <!--environments的default属性来指定使用哪个environment标签-->
    <environments default="development">
        <environment id="development">
            <!--transactionManager标签用于配置数据库管理方式-->
            <!--type="JDBC":可以进行事务的提交和回滚操作-->
            <!--type="MANAGED":依赖容器完成事务管理,本身不进行事务的提交和回滚操作-->
            <!-- <transactionManager type="MANAGED"/>-->
            <transactionManager type="JDBC"/>
            <!--POOLED|UNPOOLED-->
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/school?useSSL=false"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置映射文件的位置-->
    <mappers>
        <mapper resource="mappers/StudentMapper.xml"></mapper>
    </mappers>
</configuration>
3、创建表
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(10) NOT NULL,
  `name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(10) NOT NULL,
  `gander` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `student` VALUES (1, '白杰', 19, '男');
INSERT INTO `student` VALUES (2, '连宇栋', 19, '男');
INSERT INTO `student` VALUES (3, '邸志伟', 24, '男');
INSERT INTO `student` VALUES (4, '杰杰高', 11, '男');
INSERT INTO `student` VALUES (5, '中杰男', 18, '男');
INSERT INTO `student` VALUES (6, '武三水', 18, '女');
INSERT INTO `student` VALUES (7, '张志伟', 16, '男');
INSERT INTO `student` VALUES (8, '康永亮', 23, '男');
INSERT INTO `student` VALUES (9, '杨涛瑞', 22, '女');
INSERT INTO `student` VALUES (10, '王杰', 21, '男');
INSERT INTO `student` VALUES (11, 'fansl', 15, '男');
4、创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
    private int id;
    private String name;
    private int age;
    private String gander;
}
5、创建DAO定义接口方法
public interface StudentDAO {
    int insertStudent(Student student);
}
6、创建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">
<!--namespace指定Dao接口全限定名-->
<mapper namespace="com.ebay.dao.StudentDAO">
    <!--id要和接口方法名字保持一致;parameterType是指方法需要的参数类型-->
    <insert id="insertStudent" parameterType="com.ebay.pojo.Student">
        insert into student values(#{id},#{name},#{age},#{gander})
    </insert>
</mapper>
7、测试添加
@Test
public void insertStudent() {
    try {
        //加载Mybatis配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //新建一个factory,他的作用用来生产sqlSeesion
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
        System.out.println(studentDAO);
        int i = studentDAO.insertStudent(new Student(21,"路飞",19,"男"));
        sqlSession.commit();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
8、MybatisUtil工具类
private static SqlSessionFactory factory;
private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();


static {
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //新建一个factory,他的作用用来生产sqlSeesion
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static SqlSession getSqlSession(boolean isAutoCommit) {
    SqlSession sqlSession = local.get();
    if (sqlSession == null) {
        //通过SqlSessionFactory调用openSession方法获取对象时,可以通过参数设置事务是否自动提交
        sqlSession = factory.openSession(isAutoCommit);
        local.set(sqlSession);
    }
    return sqlSession;
}

public static <T extends Object> T getMapper(Class<T> c) {
    SqlSession sqlSession = getSqlSession(true);
    return sqlSession.getMapper(c);
}
9、事务管理

自动提交事务

通过SqlSessionFactory调用openSession方法获取对象时,可以通过参数设置事务是否自动提交
如果参数设置true,表示自动提交事务factory.openSession(true)

手动提交事务

当有多个事务操作时,自动提交会出现数据一致性问题,用手动提交

通过SqlSessionFactory调用openSession方法获取对象时,可以通过参数设置事务是否自动提交
如果参数设置false,表示手动提交事务factory.openSession(false)
SqlSession sqlSession=MybatisUtil.getSqlSession(false);
try {
    StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
    System.out.println(studentDAO);
    //事务操作1
    int i = studentDAO.insertStudent(new Student(216,"小白",19,"男"));
    //事务操作2...
    sqlSession.commit();
} catch (Exception e) {
    sqlSession.rollback();
    e.printStackTrace();
}

三、Mybatis的CRUD操作

1、简单删改查操作

StudentDAO

//删除
int deleteStudentById(int id);
//修改
int updateStudentByName(Student student);
//查询所有
List<Student> selectAllStudent();

StudentMapper.xml

<delete id="deleteStudentById">
    delete  from student where id=#{id}
</delete>

<update id="updateStudentByName" parameterType="com.ebay.pojo.Student">
    update student set`name`=#{name} ,age=#{age},gander=#{gander}  where `id`=#{id}
</update>
<!--resultType:指定查询结果封装的对象的实体类-->
<!--resultMap标签用于定义实体类与数据表的映射关系(ORM)-->
<resultMap id="studentMap" type="com.ebay.pojo.Student">
    <!--column代表数据库列的名字,property对应实体类的属性值 -->
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <result column="age" property="age"></result>
    <result column="gander" property="gander"></result>
</resultMap>
<select id="selectAllStudent"  resultMap="studentMap">
    select * from student
</select>

StudentDAOTest.java测试类

@Test
public void deleteStudent() {
    StudentDAO studentDAO= MybatisUtil.getMapper(StudentDAO.class);
    studentDAO.deleteStudentById(21);
}
@Test
public void updateStudentByName() {
    StudentDAO studentDAO = MybatisUtil.getMapper(StudentDAO.class);
    studentDAO.updateStudentByName(new Student(216,"大白00",11,"女"));
}
@Test
public void selectAllStudent() {
    StudentDAO studentDAO = MybatisUtil.getMapper(StudentDAO.class);
    List<Student> studentList = studentDAO.selectAllStudent();
    for (Student students: studentList) {
        System.out.println(students.toString());
    }
}
2、多参数查询

分页查询(参数 start,pageSize)

  • 如果操作方法有一个Map类型的参数,在Mapper配置中可以直接通过#{key}获取key对应的value

  • 在StudentDAO定义方法,如果方法有多个参数,用@Param

//分页查询
List<Student> selectStudentByPage(@Param("start")int start,@Param("pageSize")int pageSize);

StudentMapper.xml

<select id="selectStudentByPage" resultMap="studentMap">
    select * from student limit #{start},#{pageSize}
</select>

StudentDAOTest.java测试类

@Test
public void selectStudentByPage() {
    StudentDAO studentDAO = MybatisUtil.getMapper(StudentDAO.class);
    List<Student> studentList = studentDAO.selectStudentByPage(1,4);
    for (Student students: studentList) {
        System.out.println(students.toString());
    }
}
3、添加操作回填生成的主键

StudentMapper.xml

<!--useGeneratedKeys:设置添加操作是否需要回填生成的主键-->
<!--keyProperty:设置回填的主键值赋值到参数对象的哪个属性-->
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="id">
    insert into student values(#{id},#{name},#{age},#{gander})
</insert>

四、Mybatis主配置文件

mybatis-config.xml是Mybatis框架的主配置文件,用于配置Mybatis数据源和属性信息
在这里插入图片描述

1、properties标签

用于设置键值对,或者加载属性文件

  • 在resources目录下创建jdbc.properties
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:3306/school?useSSL=false
mysql_username=root
mysql_password=root

在mybatis-config.xml通过properties标签引用jdbc.properties

<properties resource="jdbc.properties"/>
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <!--数据库的驱动类名-->
            <property name="driver" value="${mysql_driver}"/>
            <!--连接数据库的url字符串-->
            <property name="url" value="${mysql_url}"/>
            <!--访问数据库的用户名-->
            <property name="username" value="${mysql_username}"/>
            <!--密码-->
            <property name="password" value="${mysql_password}"/>
        </dataSource>
    </environment>
2、settings标签
<settings>
    <!--启动二级缓存-->
    <setting name="cacheEnabled" value="true"/>
    <!--启动延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>
3、typeAliases标签
<!--typeAliases标签用于实体类取别名,在映射文件中可以直接使用别名来替代实体类的全限定名-->
<typeAliases>
    <typeAlias type="com.ebay.pojo.Student" alias="Student"></typeAlias>
</typeAliases>
4、plugins标签
<!--plugins标签,用于配置Mybatis插件(分页插件)-->
<plugins>
    <plugin interceptor=""></plugin>
</plugins>

五、映射文件

1、mapper根标签

mapper文件相当于DAO接口的实现类,namespace属性要指定实现DAO接口的全限定名

2、insert标签

声明添加操作

常用属性

id属性,绑定对应DAO接口中的方法

parameterType属性,指定接口中对应方法的参数类型(可省)

useGeneratedKeys属性:设置添加操作是否需要回填生成的主键

keyProperty属性:设置回填的主键值赋值到参数对象的哪个属性

timeout属性:设置此操作的超时时间,如果不设置则一直等待

主键回填操作

<insert id="insertStudent" useGeneratedKeys="true" keyProperty="id">
    insert into student values(#{id},#{name},#{age},#{gander})
</insert>
<!--此处主键应设自增,上面的忘了 (-_-) -->
<insert id="insertStudent" >
    <selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER">
        SELECT LAST_INSERT_ID()
    </selectKey>
    insert into student(`name`,age,gander) values(#{name},#{age},#{gander})
</insert>
3、delete标签

声明删除操作

4、update标签

声明修改操作

5、select标签

声明查询操作

id属性,指定绑定方法的方法名

parameterType属性,设置参数类型

resultType属性,指定当前sql返回数据封装的对象类型(实体类)

resultMap属性,指定从数据表到实体类的字段和属性的对应关系

useCache属性,指定此查询操作是否需要缓存

timeout属性,设置超时时间

6、resulltMap
<resultMap id="studentMap" type="com.ebay.pojo.Student">
    <!--column代表数据库列的名字,property对应实体类的属性值 -->
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <result column="age" property="age"></result>
    <result column="gander" property="gander"></result>
</resultMap>
7、cache标签

设置当前DAO进行数据库操作时的缓存属性设置

<cache type="" size="" readOnly=""></cache>
8、sql和include
<sql id="stu"> id,`name`,age,gander </sql>
<select id="selectAllStudent" resultMap="studentMap">
    select <include refid="stu"/> from student
</select>

六、分页插件PageHelper

分页插件是一个独立于Mybatis之外的第三方插件

1、添加依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>
2、配置插件

在mybatis的主配置mybatis-config.xml通过plugins标签进行配置

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">          </plugin>
</plugins>
3、分页实例
StudentDAO studentDAO = MybatisUtil.getMapper(StudentDAO.class);
PageHelper.startPage(2,5);
List<Student> studentList = studentDAO.selectAllStudent();
PageInfo<Student>  pageInfo=new PageInfo<Student>(studentList);
//pageInfo中包含了数据及分页信息
List<Student> list = pageInfo.getList();
for (Student stu: list) {
    System.out.println(stu);
}

七、关联映射

1、一对一

用户和详情

1.1创建数据表
--用户信息表
CREATE TABLE users(
user_id int PRIMARY KEY AUTO_INCREMENT,
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_INCREMENT,
user_adrr VARCHAR(20) not null,
user_tel VARCHAR(20) not null,
user_desc VARCHAR(200) not null
)
1.2创建实体类

User.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private int userId;
    private String userName;
    private String userPwd;
    private String userRealname;
    private String userImg;
    private Detail detail;
}

Detail.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Detail {
    private int detailId;
    private String userAddr;
    private String userTel;
    private String userDesc;
    private int userId;
}
1.5添加操作(事务)

分两次

SqlSession sqlSession = MybatisUtil.getSqlSession(false);
try {
    //user添加
    Detail detail = new Detail(0, "江阴", "12580", "1111", 0);
    UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
    User user = new User(0, "lisi", "11111", "李四", "01.img",detail);
    userDAO.insertUser(user);
    //detail添加
    detail.setUserId(user.getUserId());
    DetailDAO detailDAO = sqlSession.getMapper(DetailDAO.class);
    detailDAO.insertDetail(detail);
    sqlSession.commit();
} catch (Exception e) {
    sqlSession.rollback();
    e.printStackTrace();
}
1.4一对一关联查询

映射文件

  • 连接查询

UserMapper.xml

    <resultMap id="userMap" type="com.ebay.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.userAddr"/>
        <result column="user_tel" property="detail.userTel"/>
        <result column="user_desc" property="detail.userDesc"/>
    </resultMap>
    <select id="queryUser" resultMap="userMap">
    SELECT user_id,user_name,user_pwd,user_realname,user_img,detail_id,user_addr,user_tel,user_desc FROM users u INNER JOIN details d on u.user_id=d.uid WHERE u.user_name =#{userName}
    </select>
  • 子查询

DetailMapper.xml

<resultMap id="detailMap" type="com.ebay.pojo.Detail">
    <id column="detail_id" property="detailId"/>
    <result column="user_addr" property="userAddr"/>
    <result column="user_tel" property="userTel"/>
    <result column="user_desc" property="userDesc"/>
    <result column="uid" property="userId"/>
</resultMap>
<select id="queryDetail" resultMap="detailMap">
    select detail_id,user_addr,user_tel,user_desc from details where uid=#{uid}
</select>

UserMapper.xml

<resultMap id="userMap" type="com.ebay.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调用子查询,关联查询一个对象-->
    <association property="detail" select="com.ebay.dao.DetailDAO.queryDetail" column="user_id"></association>
</resultMap>
<select id="queryUser" resultMap="userMap">
    SELECT user_id,user_name,user_pwd,user_realname,user_img
    FROM users
    WHERE user_name =#{userName}
</select>
2、一对多
2.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
)
2.2 创建实体类

Clazz.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Clazz {
    private int classId;
    private String className;
    private String classDesc;
    private List<Students> stus;
}

Students.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Students {
    private int stuId;//学号
    private String stuName;
    private int stuAge;
    private String stuCid;//学生所在班级的id
}
2.3一对多关联查询
  • 连接查询

ClassMapper.xml

<resultMap id="classMap" type="com.ebay.pojo.Clazz">
    <id column="cid" property="classId"/>
    <result column="cname" property="className"/>
    <result column="cdesc" property="classDesc"/>
    <!--    Clazz对象的stus属性是一个list集合,需要使用collection标签 -->
    <!--  collection 的ofType属性声明集合中元素的类型  -->
    <collection property="stus" ofType="com.ebay.pojo.Students">
        <id column="sid" property="stuId"/>
        <result column="sname" property="stuName"/>
        <result column="sage" property="stuAge"/>
        <result column="scid" property="stuCid"/>
    </collection>
</resultMap>
<select id="queryClass" resultMap="classMap">
    SELECT * FROM classes c INNER JOIN students s
    on c.cid=s.scid
    WHERE c.cid=#{classId}
</select>
  • 子查询

ClassMapper.xml

<resultMap id="classMap" type="com.ebay.pojo.Clazz">
    <id column="cid" property="classId"/>
    <result column="cname" property="className"/>
    <result column="cdesc" property="classDesc"/>
    <collection property="stus" select="com.ebay.dao.StudentsDAO.queryStudentsById" column="cid"/>
</resultMap>
<select id="queryClass" resultMap="classMap">
    SELECT * FROM classes where cid=#{classId}
</select>

StudentsMapper.xml

<resultMap id="studentsMap" type="com.ebay.pojo.Students">
    <id column="sid" property="stuId"/>
    <result column="sname" property="stuName"/>
    <result column="sage" property="stuAge"/>
    <result column="scid" property="stuCid"/>
</resultMap>
<select id="queryStudentsById" resultMap="studentsMap">
    select * from  students where scid=#{stuCid}
</select>

多对一关联查询类似于一对一

3、多对多
3.1创建数据库

学生(m)对课程(n)

-- 学生信息表(如上)
-- 课程信息表
CREATE TABLE courses(
course_id int PRIMARY KEY auto_increment,
course_name varchar(50) not null
)
-- 选课信息表/成绩表(学号、课程号、成绩)
CREATE TABLE grades(
sid char(5) not null,
cid int not null,
score int not null
)
3.2关联查询

查询学生时,同时查询学生选择的课程

Student.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Students {
    private int stuId;//学号
    private String stuName;
    private int stuAge;
    private List<Course> courses;//学生选择的课程
}

Course.java

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    private int courseId;
    private String courseName;
}

根据课程编号查询课程时,同时查询选择了这门课程的学生

Student.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Students {
    private int stuId;//学号
    private String stuName;
    private int stuAge;
}

Course.java

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    private int courseId;
    private String courseName;
    private List<Student> students;
}

CourseMapper.xml

<resultMap id="courseMap" type="com.ebay.pojo.Course">
    <id column="course_id" property="courseId"/>
    <result column="course_name" property="courseName"/>
    <collection property="students" ofType="com.ebay.pojo.Students">
        <id column="sid" property="stuId"/>
        <result column="sname" property="stuName"/>
        <result column="sage" property="stuAge"/>
    </collection>
</resultMap>
<select id="queryStudentByCourse" resultMap="courseMap">
    SELECT * FROM courses c INNER JOIN grades g INNER JOIN  students s
    ON c.course_id=g.cid and g.sid=s.sid
    where c.course_id=#{courseId}
</select>

八、动态SQL

1.什么是动态SQL?

根据查询条件动态完成SQL的拼接

2.动态SQL使用案例
2.1 创建数据表
CREATE TABLE members(
member_id int PRIMARY KEY auto_increment,
member_nick varchar(20) not null UNIQUE,
member_gender char(2) not null,
member_age int not null,
member_city varchar(30) not null
)
2.2创建实体类

Member.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Member {
    private Integer memberId;
    private String memberNick;
    private String memberGender;
    private Integer memberAge;
    private String memberCity;
}
2.3创建DAO

MemberDAO.java

//在多条件查询中,如果查询条件不确定,可以使用HashMap做参数
List searchMember(HashMap<String,Object> params);
//也可以定义专门用于存放查询条件的实体类存放参数
List searchMember(MemberSearchCondition memberSearchCondition);

public interface MemberDAO {
    List<Member> searchMember(Member member);
}
2.4动态SQL使用

MemberMapper.xml

2.4.1 if
<resultMap id="memberMap" type="com.ebay.pojo.Member">
    <id column="member_id" property="memberId"/>
    <result column="member_nick" property="memberNick"/>
    <result column="member_gender" property="memberGender"/>
    <result column="member_age" property="memberAge"/>
    <result column="member_city" property="memberCity"/>
</resultMap>

<select id="searchMember" resultMap="memberMap">
    select * from members
    where 1=1
    -- memberNick参数对象的属性/参数map的key
    <if test="memberNick !=null">
        and member_nick=#{memberNick}
    </if>
    <if test="memberAge !=null">
        and member_age=#{memberAge}
    </if>
</select>
2.4.2 where
<select id="searchMember" resultMap="memberMap">
    select * from members
    <where>
        -- memberNick参数对象的属性/参数map的key
        <if test="memberNick !=null">
            and member_nick=#{memberNick}
        </if>
        <if test="memberAge !=null">
            and member_age=#{memberAge}
        </if>
    </where>
</select>
2.4.3 trim
select * from members
<trim prefix="where" prefixOverrides="and|or" suffix="order by member_age">
    <if test="memberNick !=null">
        and member_nick=#{memberNick}
    </if>
    <if test="memberAge !=null">
        and member_age=#{memberAge}
    </if>
</trim>
2.4.4 foreach

Member.java

List<Member> searchMemberByCity(List<String> cities);

MemberMapper.xml

<select id="searchMemberByCity" resultMap="memberMap">
    select * from members where member_city
    in
    <foreach collection="list" item="cities" separator="," open="(" close=")">
        #{cities}
    </foreach>
</select>

九、模糊查询

1.模糊查询实现

Member.java

List<Member> searchMemberByNick(@Param("keyWord") String keyWord);

MemberMapper.xml

<select id="searchMemberByNick" resultMap="memberMap" parameterType="java.lang.String">
    select * from members where member_nick like '%${keyWord}%'
</select>
2.#与$的区别
  • #{key} 表示获取参数,先完成sql编译(预编译),预编译之后再将获取的参数设置sql中
  • ${key} 表示获取参数,先获取参数的值拼接到sql语句中,再编译执行sql语句

十、Mybatis日志配置

Mybatis作为一个封装好的ORM框架,其运行过程我们没法跟踪,为了让开发者了解Mybatis执行流程及每个执行步骤所完成的工作,Mybatis框架本身继承了log4j日志框架,对运行的过程进行跟踪记录。我们只需对Mybatis进行相关的日志配置,就可以看到Mybatis运行过程中的日志信息。

1.添加依赖
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
2.添加日志配置文件
  • 在resources目录下创建名为log4j.properties文件
  • log4j.properties文件配置日志输出的方式
# 声明日志的输出级别,及输出方式
# ERROR WARN INFO DEBUG
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 定义日志的打印格式 %t:表示线程名称  %5p:日志级别 %msg:日志信息 %m%n:日志换行
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %msg %m%n
3.日志信息的级别

在使用日志框架输出日志信息的时候,会根据输出的日志信息的重要程度分为5个级别

级别说明
DEBUG输出调试信息
INFO输出提示信息
WARN输出警告信息
ERROR一般性错误信息
FATAL致命性错误信息

十一、配置数据库连接池-整合Druid

Mybatis作为一个ORM框架,在进行数据库操作时时需要和数据库建立连接,Mybatis支持基于数据库连接池的连接创建方式。

当我们配置Mybatis数据源时,只要配置了dataSource标签的属性值type属性值为POOLED时,就可以使用Mybatis内置的连接池管理连接。

如果我们想要使用第三方的数据库连接池,则需进行自定义配置。

1.常见的连接池
  • DBCP
  • C3P0
  • Druid
  • Hikari
2.添加Druid的依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.5</version>
</dependency>
3.创建Druid连接池工厂
public class DruidDataSourceFactory extends PooledDataSourceFactory {
    public DruidDataSourceFactory() {
        this.dataSource=new DruidDataSource();
    }
}
4.将DruidDataSourceFactory配置给Mybatis数据源
<transactionManager type="JDBC"/>
<!-- POOLED使用Mybatis内置连接池实现的-->
<!-- Mybatis需要一个连接池工厂,这个工厂可以产生数据库连接池PooledDataSourceFactory-->
<dataSource type="com.ebay.utils.DruidDataSourceFactory">
    <!--数据库的驱动类名-->
    <property name="driverClass" value="${mysql_driver}"/>
    <!--连接数据库的url字符串-->
    <property name="jdbcUrl" value="${mysql_url}"/>
    <!--访问数据库的用户名-->
    <property name="username" value="${mysql_username}"/>
    <!--密码-->
    <property name="password" value="${mysql_password}"/>
</dataSource>

十二、Mybatis缓存

Mybatis是基于JDBC的封装,使数据量操作更加便捷;Mybatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化:

  • 在Mybatis引入了缓存机制,用于提升Mybatis的检索效率
  • 在Mybatis引入了延迟加载机制,用于减少对数据库不必要的访问
1.缓存的工作原理

缓存,就是存储数据的内存

在这里插入图片描述

Mybatis缓存分为一级缓存和二级缓存

2.一级缓存

一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配的缓存内存,无需手动开启可直接使用;多个SqlSession的缓存是不共享的。

特性:

1、如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存中存储的数据

2、如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致;

3、当我们进行在查询时想要跳过缓存直接查询数据库,则可以通过sqlSession.clearCache();来清除当前sqlSession的缓存

4、如果第一次查询之后第二次查询之前,使用当前sqlSession执行了修改操作,此修改操作会使第一次查询缓存的数据失效,因此第二次查询会再次访问数据库。

测试代码:

public void searchMemberByNick() {
    SqlSession sqlSession = MybatisUtil.getSqlSession(false);
    MemberDAO memberDAO1 = sqlSession.getMapper(MemberDAO.class);
    List<Member> list = memberDAO1.searchMemberByNick("黄");
    System.out.println(list);
    System.out.println("_-----------------------------------------");
    list.get(0).setMemberAge(66);
    //sqlSession.clearCache();清除缓存
    MemberDAO memberDAO2 = sqlSession.getMapper(MemberDAO.class);
    List<Member> list1 = memberDAO2.searchMemberByNick("黄");
    System.out.println(list1);
}
两次查询与数据库数据不一致问题

在这里插入图片描述

3.二级缓存

二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的SqlSession可以共享二级缓存;在应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享。

特性:

1、二级缓存默认没有开启,需要在mybatis-config.xml的settting标签开启

2、二级缓存只能缓存实现序列化接口的对象

  • 在mybatis-config.xml开启使用二级缓存
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • 在需要使用二级缓存的Mapper文件中配置cache
<cache
       eviction="FIFO"
       flushInterval="60000"
       size="512"
       readOnly="true"/>

eviction:可用的清除策略有:

  • LRU– 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU

flushInterval(刷新间隔):属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目):属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读):属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false

  • 被缓存的实体类实现序列化接口
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Member implements Serializable {
    private Integer memberId;
    private String memberNick;
    private String memberGender;
    private Integer memberAge;
    private String memberCity;
}
  • 测试
@Test
public void searchMemberByNick() {
    SqlSessionFactory factory = MybatisUtil.getSqlSessionFactory();
    //1.多个SqlSession对象必须来自与同一个SqlSessionFactory
    SqlSession sqlSession1 = factory.openSession();
    SqlSession sqlSession2 = factory.openSession();
    MemberDAO memberDAO1 = sqlSession1.getMapper(MemberDAO.class);
    List<Member> list = memberDAO1.searchMemberByNick("黄");
    System.out.println(list);
    //2.第一次查询之后执行sqlSession1.commit();会将当前SqlSession查询结果缓存到二级缓存
    sqlSession1.commit();
    System.out.println("_-----------------------------------------");
    MemberDAO memberDAO2 = sqlSession2.getMapper(MemberDAO.class);
    List<Member> list1 = memberDAO2.searchMemberByNick("黄");
    System.out.println(list1);
}
查询操作的缓存开关

useCache=“false”

<select id="searchMemberByNick" resultMap="memberMap" useCache="false">
    select * from members where member_nick like '%${keyWord}%'
</select>

十三、延迟加载

延迟加载——如果在Mybatis开启了延迟加载,在执行子查询(至少查询两次及以上)时,默认只执行第一次查询,当用到子查询结果时,才会触发子查询的执行,如果无需使用子查询结果,则子查询不会执行。

fetchType=“lazy”

<association property="detail" select="com.ebay.dao.DetailDAO.queryDetail" column="user_id" fetchType="lazy">
</association>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值