mybatis

mybatis

通过官网查看 https://mybatis.org/mybatis-3/zh/getting-started.html

1. 什么是框架

框架是一整套解决问题的方案, 里面并没有具体的业务逻辑, 是一个半成品的软件. 

2. mybatis概述

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 
Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

3. mybatis快速入门

3.1 引入依赖

如果是maven工程, 通过pom.xml引入依赖

    <!--引入mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.0</version>
    </dependency>

3.2 核心配置文件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 default="mysql">
        <!--mybatis具体的配置环境信息-->
        <environment id="mysql">
            <!--事务管理  采用JDBC事务-->
            <transactionManager type="JDBC"/>
            <!--数据源  从哪里引过来的   采用池子类型-->
            <dataSource type="POOLED">
                <!--数据源的四大组件-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/java31"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--映射器
        ORM思想 : object relationship model
        把实体类和数据库中的表产生映射一一对应关系
        model类                   数据库表
           属性                     字段
            id                       id
            username                 username
            address                  address
            gender                   gender
        在映射时要确保实体类的属性名称,数据类型和表中的字段名称,数据类型高度保持一致
        好处 : 封装便利
    -->
    <mappers>
        <!--XXXMapper.xml,存放的就是一些操作数据库的配置信息-->
        <mapper resource="com/zy/dao/UserMapper.xml"/>

    </mappers>
</configuration>

因为是映射XXXmapper.xml的,所以XXXmapper.xml需要放在resources的文件夹下,并且全路径需要一致,比如 com.zy.mapper
在这里插入图片描述

3.3 创建dao层接口和实体类

实体类的属性和数据库表中的字段需要保持一致

3.4 配置Mapper信息

创建XXXMapper.xml,但是需要XXXMapper.java路径保持一致

<?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 命名空间
    引入对应的Mapper接口文件,形成关联映射


-->
<mapper namespace="com.zy.dao.UserMapper">
    <!--
        mapper.xml文件                  接口文件
               id                          方法名称
               resultType                  返回值类型(没有集合类型,填写它的泛型(全路径 ))
               parameterType               方法参数的数据类型
    -->
    <select id="getAllUser" resultType="com.zy.pojo.User">
        select * from user
    </select>
</mapper>

3.5 测试配置信息

加载核心配置文件
创建sqlSessionFactoryBuilder对象  
通过Builder对象创建SqlSessionFactory对象
通过SqlSessionFactory对象调用openSession方法得到SqlSession
通过sqlSession进行增删改
//1. 加载mybatis核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //2.创建SqlSessionFactory工厂对象
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = factoryBuilder.build(inputStream);
        //3. 通过工厂对象得到SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4. 通过Class对象反射得到实体类对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //5. 通过userMapper实现类对象调用方法查找数据库
        List<User> allUser = userMapper.getAllUser();
        for (User user : allUser) {
            System.out.println(user);
        }

4. 注意事项

4.1 写(增删改)操作的事务提交

在对数据库执行写操作(增删改)时,需要提交事务sqlSession.commit()

sqlSession.commit();//提交事务,让修改的数据持久化,存储到磁盘中

4.2 mapper.xml的#{}

在XXXMapper.xml中

<select id="getOneUserById" parameterType="int" resultType="com.zy.pojo.User">
        select * from user where u_id= #{u_id}
        <!--
            #{id} ==> OGNL表达式
            它主要是通过对象的取值方法来获取数据,在写法上把get省略掉 ==>映射get
            EL表达式 ==>  ${user.username} 出现JSP页面  ==>类似于OGNL表达式
        -->
    </select>

4.3 模糊查询

写模糊查询的时候sql可以这样写

<select id="fuzzySelectByUsername" resultType="com.zy.pojo.User">
        select * from user where username like #{username}
    </select>

在赋值时需要这样 : “%值%”

 List<User> list = userMapper.fuzzySelectByUsername("%小%");

4.4 注解开发

注解开发
在接口的抽象方法上使用@Select,@Insert,@Update,@Delete,在括号里写上sql语句,
然后在XXXMapper.xml就不用写相应的标签和sql 了

//注解开发
    @Select("select * from user where u_id = #{u_id}")//userMapper.xml就不用再写sql
    User getOneUserById(int id);

4.5 配置文件的映射关系

配置文件(mybatis-config.xml)中的映射
(1). 映射xml  :  <mapper resource="com/zy/dao/UserMapper.xml"/>
     此时XXXMapper.xml需要放在resource资源包
(2). 映射接口 : <mapper class="com.zy.mapper.UserMapper"/>
(3). 映射包 : <package name="com.zy.mapper"/>

4.6 起别名

在mybatis-config.xml里

    <!--给包起别名
        在mapper.xml的resultType,parameterType每次都要写全路径 :
        resultType= com.zy.pojo.User,
        起别名之后可以直接写类名resultType=User
    -->
    <typeAliases>
        <!--配置单个类的别名-->
        <!--<typeAlias type="com.zy.pojo.User"/>-->
        <!--整个包-->
        <package name="com.zy.pojo"/>
    </typeAliases>

4.7 表中字段为a_bb时,实体类属性名称会不一致

当数据库表为a_bb时,实体类对应的属性一般不会写a_bb,一般为 表名+ bb
但是因为字段和属性名称不一致,所以数据库表的信息装不到实体类里
所以可以在sql语句通过起别名的方式(不推荐),该别名与实体类的属性名一致
    <select id="getAllCustomer" resultMap="customerMap">
        select r_id as id ,r_address as address from customer
    </select>

使用resultMap使得实体类属性和表中的字段一一对应(推荐)

    <!--使用resultMap使得实体类的属性和数据库表中字段一一对应关系,
        需要在操作数据库标签(如select)里使用resultMap属性=resultMap标签的id属性使他们关联起来-->
    <resultMap id="customerMap" type="Customer">
        <id property="id" column="id"/>
        <result property="address" column="r_address"/>
        <result property="level" column="r_level"/>
        <result property="name" column="r_name"/>
        <result property="phone" column="r_phone"/>
        <result property="source" column="r_source"/>
    </resultMap>
    <select id="getAllCustomer" resultMap="customerMap">
        select * from customer
    </select>

4.8 当多条件查询时

采用索引的方式,适合参数比较少(不推荐)

    <select id="getUserByUsernameAndPassword" resultType="User">
        <!--
           多条件查询时 不需要parameterType
           Available parameters are [arg1, arg0, param1, param2]
           采用索引的方式
        -->
        select * from user where username = #{param1} and password = #{param2}
    </select>

当参数比较多时,使用实体类的方式,把条件都封装到实体类里面

    <select id="getUserByUsernameAndPassword" resultType="User"  parameterType="User">
        select * from user where username = #{username } and password = #{password }
    </select>

(推荐)使用注解@Param()

 User selectUserByUsernameAndPassword(@Param("username") String username,@Param("password") String password);

否则可能回报这个错误 :
There is no getter for property named ‘Xxxxx’ in 'class java.lang.String

4.9 Mybatis的内置日志(log4j)

引入依赖

    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>

log4j.properties配置文件

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

4.10 数据源配置文件db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/数据库名称?CharacterEncoding=UTF-8
jdbc.username=用户名
jdbc.password=密码

在mybatis-config.xml的configration标签内引入db.properties

<!--引入外部的配置文件db.properties  数据源的组件-->
    <properties resource="db.properties"/>

在这里插入图片描述

5. 输入映射(parameterType)

简单类型

基本类型 ==>整形为主
String字符串

复杂类型

pojo
Plain Ordinary Java Object 简单的Java对象,实际上是JavaBean
当传入的参数较多时,可以把参数封装到pojo,以pojo作为参数进行传递
pojo的包装类
格式 : 类名+Vo
内部至少包含一个普通类,可以进行多条件查询
一般用于多个对象组成的查询条件

public class UserVo {
    private User user;//也可以使用继承User
    private Customer customer;
    <select id="selectUserByUsernameAndCustomerName" parameterType="userVo" resultType="UserVo">
        select * from user,customer where username like '%' #{user.username} '%' and name = #{customer.name}
    </select>

6. 输出映射(resultType)

resultType属性可以指定结果集的类型,它支持基本类型和JavaBean类型
parameterType和resultType一样,如果提前注册过类型的别名,可以直接使用别名,如果没有注册过就需要写全限定类名
注意 : 实体类中属性名称必须和表字段(sql查询语句中字段名称)保持一致,否则无法封装

简单类型

基本类型 ==>整形
String字符串

<select id = "selectUserCount" resultType = "Integer">
   select count(*) from user
</select>

<select id = "queryUserName" parameterType = "int" resultType = "String">
	select username from user  where id = #{id}
</select>

复杂类型

pojo ==>单个对象(一条记录) , resultType=“user”
pojo列表 ==>多个对象,多条记录 ,存在数组或集合当中resultType=“泛型”

问题 : 当实体类属性和表中字段名称不一致时,应该怎么封装

1 使用别名查询(不推荐使用)

<select id = "findAllUsers" resultType = "user">
	select id as userId,username as userName,birthday as userBirthday,sex as userSex
    , address as userAddress from user
</select>

如果查询sql语句较多时,使用别名不方便.

2 resultMap(推荐使用)

如果查询sql语句较多时,我们可以使用resultMap进行实体类属性和表中字段进行映射.
首先定义resultType,把实体类属性和表字段一一映射,
然后在select标签引入resultMap结果集,
此外,resultMap还可以进行将查询的结果集映射为复杂的pojo,比如在查询结果映射对象时,
对象可以包括pojo,和List实现一对一查询和一对多查询.
<!--id映射 : <id column = "表字段名" property="实体类属性名" />
非主键映射 : <result column = "表字段" property="实体类属性名" />-->

<resultMap id="customerMap" type="Customer">
        <id property="id" column="id"/>
        <result property="address" column="address"/>
        <result property="level" column="level"/>
        <result property="name" column="name"/>
        <result property="phone" column="phone"/>
        <result property="source" column="source"/>
    </resultMap>
    <select id="getAllCustomer" resultMap="customerMap">
        select * from customer
    </select>
 一对一映射 
<association property="实体类属性名"    javaType="实体类" />
当输出结果时,内部包含另外一个pojo,使用resultMap和pojo中属性映射时,可以先在类中声明该pojo属性
其次,在mapper.xml文件中通过resultMap使用<association property="实体类属性名"  javaType="实体类" />进行关联
   <!--查询所有用户信息 里面关联部门信息-->
    <resultMap id="userMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="address" column="address"></result>
        <result property="gender" column="gender"></result>
        <!--映射复杂的pojo类型 一一映射 -->
       <association property="department" javaType="Department">
            <id property="id" column="d_id"/>
            <result property="departmentName" column="d_name"/>
            <result property="departmentDesc" column="d_desc"/>
            <result property="departmentUpdate" column="d_update"/>
        </association>
    </resultMap>

    <!-- List<User> getTotalUser();-->
    <select id="getTotalUser" resultMap="userMap">
        select * from user as u,department as d  where u.u_did = d.d_id
    </select>
一对多映射 
<collection property="实体类属性名" ofType="容器中的数据类型"/>
查询角色时,首先展示角色信息,还要展示该角色下的所有用户信息
首先需要在实体类中定义pojo属性,属性类型为容器类型List,
其次在Mapper.xml文件中定义resultMap的一对多映射
在select标签引入resulrtMap引入
<!--使用resultMap 让实体类的属性名称和表中的字段名称保持一致-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="r_id"></id>
        <result property="roleName" column="r_name"></result>
        <result property="roleDesc" column="r_desc"></result>
        <result property="roleUpdateTime" column="r_updateTime"></result>
        <!--角色和用户时一对多关系-->
        <!--
              ofType:对于容器类型我们采用指定容器数据的类型,使用属性ofType
              javaType: 代表是users本身的类型,List类型
        -->
        <collection property="users" ofType="user" >
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="address" column="address"></result>
            <result property="gender" column="gender"></result>
        </collection>
   </resultMap>
   <select id="getAllRoles2" resultMap="roleMap">
        <!--采用起别名方式-->
        select * from role
   </select>

7. 动态sql

动态 SQL 是 MyBatis 的强大特性之一,解决根据不同条件拼接 SQL 语句的不便.
可以借助功能强大的基于 OGNL 的表达式

7.1 if

<select id="selectUserByUsername" resultType="User" parameterType="string">
    select * from user where 1 = 1
    <if test="username != null">
        and username = #{param1}
    </if>
    <if test="password != null ">
        and password like #{param2}
    </if>
</select>

7.2 choose(when,otherwise)

有时候,我们不想使用所有的条件,而是从这些条件中选择一个使用,Mybatis提供了choose标签

    <select id="selectUser" resultType="User">
        select * from user where 1 =1
        <choose>
            <when test="username != null and username != ''">
                and username = #{username}
            </when>
            <otherwise>
                and password = #{password}
            </otherwise>
        </choose>
    </select>

7.3 trim(where set)

where可以去掉第一个and
set主要用于动态更新语句. set可以用于包含需要更新的字段, 忽略其他不跟新的字段.

    <select id="queryUserByUsernameOrId" resultType="User">
        select * from user
        <where>
            <if test="u_id &lt; 6"><!--u_id < 6-->
                u_id &lt; #{param2} <!--u_id < ?-->
            </if>
            <if test="username != '' and username != null">
                and username = #{username}
            </if>
        </where>
    </select>
<update id="updateUserByNecessary" parameterType="User">
        update user
        <set>
            <if test="username != '' and username != null">
                username = #{username},
            </if>
            <if test="password != '' and password != null">
                password = #{password}
            </if>
        </set>
        <where>
            <if test="u_id &lt; 6">
                u_id = #{u_id}
            </if>
        </where>
    </update>

7.4 foreach

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。
它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach
尤其在构建in条件语句的时候使用 : select * from user where id in(1,2,4,6,7)
<sql id="selectUser">
        select * from user
    </sql>
    <select id="selectUserById" resultType="User" parameterType="list">
        <include refid="selectUser"/>
        <where>
            <!-- u_id in(1,2,3,4,7) -->
            <foreach collection="list" item="u_id" open="u_id in (" close=")"  separator=",">
                #{u_id}
            </foreach>
        </where>
    </select>

注意 : 参数为集合时, collection只能是list; 参数是数组时, collection只能是array

8. sql片段

可以把多次出现的sql语句用sql标签封装为一个片段,在使用时可以直接引用
使用include标签引用即可

<sql id="selectUser">
    select * from user
</sql>

<!--根据用户名和密码查找用户信息-->
<select id="selectUserByusernameAndPassword" resultType="user">
    <include refid="selectUser />
    <where test="username != null">
    <if test="username != null">
        username = #{usernmae}
    </if>
    <if test="password != null">
        password = #{password }
    </if>
</select>

9. 关联查询

一个模块其实就是一张表
一个模块的信息通常需要关联其他模块的信息
模块与模块之间的关联   ==> 表与表之间的关联

用户表            角色表
  1                1        从用户角度        一对一      
  n                1        从角色角度        一对多      
  对于多对多映射,可以当成两个一对多的映射, 一般会借助中间表

实体类关联
在这里插入图片描述

10. mybatis的事务

Connection  setAutoCommit(boolean autoCommit)   false代表开启事务,只影响增删改,不影响查询
操作,  mybatis默认开启事务.
可以借助于SqlSessionFactory.openSession( [boolean   autoCommit] )开启或关闭事务
SqlSession对象 commit(), 如果在mybatis使用中关闭事务,需要设置autoCommit为true

10.1什么是事务

事务是由单独的一个或多个sql语句组成, 在这个单元中, 每个sql语句都是相互依赖的,
而整个单元是一个不可分割的整体. 如果单元中某条sql语句执行异常,那么整个单元则会回滚.

10.2事务的四大特性ACID

原子性(Atomicity) : 一个事务是一个不可分割的一个整体 , 在这个整体中要么全部执行,要么全部不执行. 
一致性(Consistency) : 一个事务的执行会使数据从一个状态切换到另一个状态.但整体总和是不变的
隔离性(Isolation) : 一个事务的执行不受其他事务的干扰
持久性(Durability) : 一个事务一旦提交,会永久改变数据库的数据,数据不可逆

由事务的隔离性会引发的一些问题

脏读

  脏读是指一个事务处理过程中读取到了另一个尚未提交的事务中的数据

不可重复读

  不可重复读是指对于数据库中某个数据, 一个事务范围内多次查询却返回了不同的数据值, 这是由于查询的时间内
被另外一个事务修改并提交了

虚度(幻读)

  幻读是指事务非独立运行时发生的一种现象, 例如有两个事务A , B ,这两个事务同时对用户表user做操作,
事务A对用户表做了全局修改,把用户表中所有人的性别改为男. 这个时候事务B往用户表中插入了一条新数据,
新数据中的性别为女,并且把这个数据提交到数据库.如果这时候事务A再次查看用户表修改的数据, 发现有一条数据
的性别为女性. 对于事务A就好像产生了幻觉一样,这就是幻读

不可重复度和幻读都是读取到另一个已提交的事务数据

通过提高数据库的隔离性来解决以上问题

10.2.1隔离性的四个级别
Read uncommitted(读未提交) : 最低级别,在任何时候都是无法保证数据的安全性
Read committed(读已提交) :  解决掉脏读现象
Repeatable Read(可重复度) : 可以解决掉脏读,不可重复度现象
Serialization(串行化) : 可以理解为锁表动作,它可以解决以上所有问题

这个mybatis的事务我们可以移植到Spring中

11. mybatis的延时加载

用户表和角色表
从用户表到角色表  ==> 一一映射
public class User{
    // ...自己的属性
    private  Role role;
}
public class Role{
    private List<User> userList;
}
延时加载也叫按需加载 ,什么时候需要关联角色表,什么时候才会查询数据库
延时加载也称为懒加载
   懒加载主要是应用到**级联操作**. 懒加载的目的主要是减少内存的浪费,减轻系统或服务器的负担
   懒加载也称为按需加载. 当我调用关联的数据时才与数据库交互,否则不交互

assocation的三个属性

产生延时加载需要借助assocation的select和colume这两个属性
select属性 填写的需要级联调用的select 标签对应另外表中的id值的**全限定路径**(另一个表中对应的接口的对应方法的全限定路径) 
colume填写的是级联调用的select中的id值对应的参数,参数的名称是当前表中字段名(或sql语句中的列名)
fetchType 开启局部加载   eager立即加载    lazy延时加载

设置全局性的延时加载

在mybatis-config.xml里配置

  <!--需要放在属性(properties)前,别名(typeAliases)后-->
    <settings>
        <!--全局限性的开启延时加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

11.1使用assocation(一一映射)实现延时加载

在User类中添加Role属性对象,和对应的setget方法

 private Role role;//因为一个用户只有一个角色,即一个User只有一个Role

在UserMapper接口

//查询用户表所有用户信息
    List<User> getAllUser();

在RoleMapper接口

Role selectRoleById(int r_id);

在UserMapper.xml

<!--映射对应的接口文件-->
<mapper namespace="com.zy.dao.IUserDao">

    <resultMap id="Map" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="address" column="address"/>
    <result property="age" column="age"/>
    <result property="gender" column="gender"/>
    <result property="u_rid" column="u_rid"/>
    <result property="u_did" column="u_did"/>
    </resultMap >
<resultMap id="userMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="address" column="address"/>
    <result property="age" column="age"/>
    <result property="gender" column="gender"/>
    <result property="u_rid" column="u_rid"/>
    <result property="u_did" column="u_did"/>
    <!--一一映射  级联-->                                  <!--把user的u_rid传递给selectRoleById()方法-->
    <association property="role" javaType="Role" select="com.zy.dao.IRoleDao.selectRoleById" column="u_rid" >
        <id property="roleId" column="r_id"/>
        <result property="roleName" column="r_name"/>
        <result property="roleDesc" column="r_desc"/>
        <result property="roleUpdateTime" column="r_updateTime"/>
    </association>

</resultMap>

<select id="getAllUser" resultMap="userMap"><!--引用id为userMap的resultMap-->
    select * from user
</select>

在RoleMapper.xml

<!--映射对应的接口文件-->
<mapper namespace="com.zy.dao.IRoleDao">

    <resultMap id="Map" type="role">
    <id property="roleId" column="r_id"/>
    <result property="roleName" column="r_name"/>
    <result property="roleDesc" column="r_desc"/>
    <result property="roleUpdateTime" column="r_updateTime"/>
    </resultMap>
    <!--根据id查询角色信息,延时加载时在IUserDao.xml的association会
        根据select属性的方法路径找到selectRoleById方法,并把column的id值传递过来
    -->
    <select id="selectRoleById" resultMap="Map" parameterType="int"><!--引用id为Map的resultMap-->
        select  * from role where r_id = #{r_id}
    </select>

11.2使用conlletion(一对多映射)实现延时加载

在Role类里添加

private List<User> users;//因为一个角色1可以有多个用户,所以用List

在RoleMapper接口

//查询所有的角色信息
    List<Role> fetAllRole();

在UserMapper接口

//根据id值查询所有用户信息
    List<User> getUserById(int id);

在RoleMapper.xml

<!--使用resultMap 让实体类的属性名称和表中的字段名称保持一致-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="r_id"/>
        <result property="roleName" column="r_name"/>
        <result property="roleDesc" column="r_desc"/>
        <result property="roleUpdateTime" column="r_updateTime"/>
        <!--角色和用户时一对多关系-->
        <!--
              ofType:对于容器类型我们采用指定容器数据的类型,使用属性ofType
              javaType: 代表是users本身的类型,List类型
        -->
        <collection property="users" ofType="user" select="com.zy.dao.IUserDao.getUserById" column="r_id">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="age" column="age"/>
            <result property="address" column="address"/>
            <result property="gender" column="gender"/>
        </collection>
    </resultMap>
        <select id="fetAllRole" resultMap="roleMap" ><!--引用id为roleMap的resultMap-->
        select * from role
    </select>

在UserMapper.xml

    <select id="getUserById" resultMap="Map" parameterType="int"><!--引用id为Map的resultMap-->
        select * from user where u_rid = #{u_rid}
    </select>

12. mybatis的缓存

 mybatis中的缓存分为一级缓存和一级缓存.

1 什么是缓存?

一些存在于内存当中的一些数据需要使用的空间

2 为什么使用缓存?

尽量降低和数据库交互,效率和性能会大大提高

3 什么样的数据适合在缓存中 ,什么数据不适合存与缓存中?

适合于 : 经常查询的 ,并且数据不太重要的,不需要经常改变的数据
不适合 : 重要的数据,经常变化的数据,数据的变化可能对结果产生一定的影响

12.1 一级缓存

一级缓存是基于SqlSession级别的缓存,这个一级缓存是默认存在的.
只要SqlSession没有执行刷新或关闭动作,那么一级缓存就一直存在
 List<User> userList = userDao.getUserByAddress("%郑州%");
        for (User user : userList) {
            System.out.println(user);
        }
        
        //测试mybatis的一级缓存
        System.out.println("=========================================");
        List<User> list = userDao.getUserByAddress("%郑州%");
        for (User user : list) {
            System.out.println(user);
        }
    }

在这里插入图片描述

在第一次查询和第二次查询之间清除了缓存,那么第二次会去数据库查找

        //清楚sqlSession的缓存
        sqlSession.clearCache();
在第一次查询和第二次查询之间关闭了sqlSession,那么第二次查询会报错

第一次查询和第二次查询使用不同的sqlsession,那么第二次查询需要到数据库查询

如果对数据进行写查找,那么缓存就会消失,需要到数据库进行查找

总结 : 一级缓存是sqlSession范围内的缓存,当调用sqlSession的修改,删除,添加,commit,close,
clearCache方法后就会清除一级缓存

12.2二级缓存

二级缓存是mapper,SqlSessionFactory级别的.多个sqlSession可以共用二级缓存,是跨sqlSession的.

步骤 :

让mybatis支持二级缓存,在mybatis-config.xml配置

 <!--需要放在属性(properties),别名(typeAliases)-->
    <settings>
        <!--全局限性的开启延时加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--开启全局二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

让当前的映射文件mapper.xml文件也支持二级缓存

 <!--让UserMapper.xml支持二级缓存-->
    <cache/>

让当前的sql操作支持二级缓存,在标签中配置

<!--根据address查询用户信息,测试mybatis的二级缓存   useCache="true"支持二级缓存-->
    <select id="getUserByAddresses" useCache="true" resultType="User" parameterType="string">
        select * from user where address like #{address}
    </select>

测试

 @Test
    public void testGetUserByAddresses() {
        List<User> userList = userDao.getUserByAddresses("%郑州%");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
        System.out.println("====================================");

        //创建新的sqlSession
        SqlSession sqlSession = factory.openSession(true);
        IUserDao mapper = sqlSession.getMapper(IUserDao.class);
        List<User> userList01 = mapper.getUserByAddresses("%郑州%");
        for (User user : userList01) {
            System.out.println(user);
        }
        System.out.println("======================================");
        System.out.println(userList == userList01);//false 因为两个sqlSession不是同一个对象

    }

结果 : 只查询了一次数据库 , 并且实体类需要实现序列化,建议实体类都实现序列化
在这里插入图片描述

13. 连接池

提供了三种方案 : UNPOOLED, POOLED, JNDI.
我们一般使用POOLED : 利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化
和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

在这里插入图片描述

14. mybatis的注解开发

替代xml配置开发, 减少xnl文件的使用
不用写mapper.xml,可以直接在接口使用
注解功能
@Select("sql语句")    相当于select标签
@Update("sql语句")  相当于update标签
@Delete("sql语句")   相当于delete标签
@Insert("sql语句")    相当于insert标签
@ResultMap(value = "userMap")//等价于select标签的resultMap属性

@Results(        //等价于resultMap标签,
     id = "userMap"   ,        //resultMap的属性id
     value = {
             @Result(id = true,property = "属性Id", column = "字段Id"),//主键id
             @Result(property = "属性",column = "字段"),//相当于result标签
             @Result(
                            one=@One(
                                            fetchType = FetchType.LAZY   //延迟加载    
                            )
             )
     }
)

@SelectKey(keyProperty = "userId",keyColumn = "id",
           resultType = Integer.class,//返回值类型
           before = false,//执行之后返回
           statement = "SELECT LAST_INSERT_ID()" //返回id的sql语句
) //等价于selectKey标签

14.1 一一映射

使用注解开发的一一映射关系
UserMapper接口

    //查询所有用户信息
    @Results(//等价于resultMap标签,
            id = "userMap"   ,        //resultMap的属性id
            value = {
                     //使实体类的属性和表字段一一对应
                    @Result(id = true,property = "userId", column = "id"),//主键id
                    @Result(property = "username",column = "username"),
                    @Result(property = "userAge",column = "age"),
                    @Result(property = "userAddress",column = "address"),
                    @Result(property = "userGender",column = "gender"),
                    @Result(property = "userDid",column = "u_did"),
                    @Result(property = "userRid",column = "u_rid"),
                    //表示一一映射关系,把u_did传递给接口IDepartment的selectDepartmentById方法
                    @Result(
                     column = "u_did",
                     property = "department",
                     javaType = Department.class,
                     //表示一一映射关系
                     one = @One(select = "com.zy.dao.Department.selectDepartmentById")
                    )
            }

    )
    @Select("select * from user") //等价于select标签,
    List<User> getAllUser();

DepartmentMapper接口

    //封装一个department
    @Select("select * from department where d_id = #{d_id}")
    @Results(
            id = "departmentMap",
            value = {
                    @Result(id = true ,property = "id",column = "d_id"),
                    @Result(property = "departmentName",column = "d_name"),
                    @Result(property = "departmentDesc",column = "d_desc"),
                    @Result(property = "departmentUpdate",column = "d_update"),
            }
    )
    Department selectDepartmentById(int id);

14.4 一多映射

在DepartmentMaaper接口
使用@Result注解实现实体类和数据库表中字段一一映射,其中有一个id属性属于主键id的
因为一个部门有多个员工所以javaType用List.class
many=@Many()相当于mapper.xml的ResultMap标签的colletion标签,会把column的值传递给select指定的方法
 //查询所有部门信息
    @Select("select * from department")
    @Results(
            value = {
                    @Result(id = true ,property = "id",column = "d_id"),
                    @Result(property = "departmentName",column = "d_name"),
                    @Result(property = "departmentDesc",column = "d_desc"),
                    @Result(property = "departmentUpdate",column = "d_update"),
                    @Result(
                            column = "d_id",
                            property = "users",
                            javaType =List.class,
                            many = @Many(select = "com.zy.dao.IUserDao.selectUserById")
                    )
            }
    )
    List<Department> selectAllDepartment();

在UserMapper接口中

//根据id查询用户信息
    @Select("select * from user where u_did = #{did}")
    //@ResultMap(value = "userMap")//等价于select标签的resultMap属性
    @Results(//等价于resultMap标签,
                  //resultMap的属性id
            value = {
                    @Result(id = true, property = "userId", column = "id"),//主键id
                    @Result(property = "username", column = "username"),
                    @Result(property = "userAge", column = "age"),
                    @Result(property = "userAddress", column = "address"),
                    @Result(property = "userGender", column = "gender"),
                    @Result(property = "userDid", column = "u_did"),
                    @Result(property = "userRid", column = "u_rid"),
            }
    )
    User selectUserById(int did);

15. mybaris的逆向工程

mapper.xml    xml映射文件
mapper.java   接口文件
Pojo          JavaBean
它会自动生成以上三个文件,这样我就不用写实体类,和单表操作的接口和xml
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值