mybatis学习笔记

mybatis

1.mybatis概述

1. 1 什么是mybatis

1:Hibernate就是一个持久层的的框架。对JDBC做了轻量级封装
2:Mybatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射

1.2 mybatis概述

1:它是基于Java编写的持久层框架,使开发者不必关心传统jdbc的api,只关心sql语句本身

2:mybatis 通过 xml或注解的方式将要执行的各种 statement 配置起来

3:采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作

2.mybatis的CRUD操作

2.1 mybatis查询所有的步骤

1.创建工程

2.导入maven坐标

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

3.创建实体类

public class User implements Serializable {

    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;
}

4.导入log4j.properties文件

查询所有

5.创建SqlMapConfig.xml(省略)

<typeAliases>用于指定别名
<environments>配置环境
	<environment>
		<transactionManager type="JDBC">配置事务管理策略
		<dataSource type="POOLED">配置数据区连接方式
			<property name="" value=""/>配置数据库连接参数
<mappers>
	 <package name="com.cyannote.dao"/>用于指定dao接口所在的包

6.创建UserDao.java

public interface UserDao {
    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();
}

7.创建UserDao.xml

 <mapper namespace="com.cyannote.dao.UserDao">
    <!--查询所有-->
    <select id="findAll" resultType="com.cyannotea.domain.User">
        select * from user
    </select>
</mapper>

8.创建测试类MybatisTest .java(省略)

2.2 #{}与${}的区别

#{}表示一个占位符号
通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
表 示 拼 接 s q l 串 通 过 {}表示拼接sql串 通过 sql{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值, pojoparameterType{}括号中只能是value。

2.3 SqlMapConfig.xml配置文件

SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)

SqlMapConfig.xml配置文件
<properties resource="jdbcConfig.properties"></properties>

settings(全局配置参数)
typeAliases(类型别名)

<!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
    <!--<package name="com.cyannote.domain"></package>-->
</typeAliases>

typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)

<package name=""/> 
注册指定包下的所有mapper接口 
如:<package name="com.caynnote.dao"/> 
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。 
应用场景:即可以使用XML配置文件,也可以使用注解。

2.4 Mybatis映射文件的SQL深入

动态SQL的标签

<!--根据条件查询-->
<select id="findByCondition" parameterType="user" resultMap="userMap">
    select * from user where 1=1
    <if test="userName != null">
        and username = #{userName}
    </if>
    <if test="userSex != null">
        and sex = #{userSex}
    </if>
</select>

动态SQL之标签

<!--where标签的使用-->
<select id="findByCondition" parameterType="user" resultMap="userMap">
    select * from user
    <where>
        <if test="userName != null">
            and username = #{userName}
        </if>
        <if test="userSex != null">
            and sex = #{userSex}
        </if>
    </where>
</select>

动态标签之标签

<!--foreach标签的使用-->
<select id="findInIds" parameterType="queryVo" resultMap="userMap">
    select * from user
    <where>
        <if test="ids != null and ids.size()>0">
            <foreach collection="ids" open=" and id in (" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </if>
    </where>
</select>

3.mybatis的多表查询

3.1 多对一(一对一):

方案一:创建新的javabean(包含两张表的字段)

第一步:sql语句
SELECT a.*,u.username,u.address FROM account a,USER u WHERE u.id = a.uid
第二步:在com.cyanote.domain中创建AccountUser.java
创建一个新的javabean

public class AccountUser extends Account implements Serializable {
	private String username;
	private String address;
}

第三步:AccountDao.java
/**

​ *查询账号和客户的信息
​ */
​ List findByAccountUser();
第四步:AccountDao.xml

<!-- 查询所有 -->
<select id="findByAccountUser" resultType="com.cyannote.domain.AccountUser">
    SELECT a.*,u.username,u.address FROM account a,user u WHERE u.id = a.uid
</select>

第五步:MybatisTest.java

方案二:直接用用Account对象封装

第一步:sql语句
select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid
第二步:修改Account.java
在Account中封装User

public class Account implements Serializable{
    private Integer id;
    private Integer uid;
    private Double money;
    private User user;

public User getUser() {
   	 	return user;
	}

public void setUser(User user) {
    	this.user = user;
	}
}

第三步:AccountDao.java

/**

*查询账号和客户的信息(方案二:直接用Account对象封装)
*/
List<Account> findByAccountUser2();

第四步:AccountDao.xml

<!--定义resultMap对象,用来封装账号信息-->
  <resultMap id="accountMap" type="account">
  <id property="id" column="aid"></id>
  <result property="uid" column="uid"></result>
  <result property="money" column="money"></result>
  <!--association用来关联对象(用于多对一,或一对一),property代表加载对象,javaType代表加载对象的数据类型,可以写成com.cyannote.domain.User-->
  <association property="user" javaType="user">
      <id property="id" column="id"></id>
      <result property="username" column="username"></result>
      <result property="address" column="address"></result>
  </association>
</resultMap>
<!-- 查询所有(方案二:直接用Account对象封装) -->
<select id="findByAccountUser2" resultMap="accountMap">
    select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid
</select>

第五步:MybatisTest.java

4.mybatis的延迟加载策略

4.1 什么是延迟加载

什么是延迟加载
在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
什么是立即加载
不管用不用,只要一调用方法,马上发起查询。
应用场景:
在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常情况下我们都是采用延迟加载。(建议)
多对一,一对一:通常情况下我们都是采用立即加载。(建议)

4.2 配置延迟加载

配置SqlMapConfig.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>
    <properties resource="jdbcConfig.properties"></properties>
    <!--需要配置延迟加载策略-->
    <settings>
        <!--打开延迟加载的开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--将积极加载改为消息加载,即按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

配置AccountDao.xml:(局部配置)

AccountDao.xml中使用fethcType属性用来控制延迟检索和立即检索:

<!--fetchType:
    eager:立即检索
    lazy:延迟检索
-->
<association property="user" javaType="user" select="com.cyannote.dao.UserDao.findById" column="uid" fetchType="eager">
</association>

只配置一处就可实现延迟加载,若两处都配置,局部配置优先级别更高.

5.mybatis缓存

Mybatis中缓存分为一级缓存,二级缓存
一级缓存:是SqlSession级别的缓存(线程级别的缓存)
二级缓存:是SqlSessionFactory级别的缓存(进程级别的缓存)
一个SqlSessionFactory存在多个SqlSession。

5.1 一级缓存(SqlSession)

​ 它指的是Mybatis中SqlSession对象的缓存。默认是开启SQLSession缓存的.

​ 当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。一级缓存中存放的是一个对象.

​ 该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用,如果没有再查询数据库。

​ 一级缓存是SqlSession 范围的缓存,当调用SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

​ 当SqlSession对象消失时,mybatis的一级缓存也就消失了。

在这里插入图片描述

​ 第一次发起查询用户id 为1 的用户信息,先去找缓存中是否有id 为1 的用户信息,如果没有,从数据库查询用户信息。 得到用户信息,将用户信息存储到一级缓存中。 如果sqlSession 去执行commit 操作(执行插入、更新、删除),清空SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

​ 第二次发起查询用户id 1 id 1

5.2 二级缓存(SqlSessionFactory)

​ 它指的是Mybatis中SqlSessionFactory对象的级别缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

​ 二级缓存的使用步骤:

​ 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)

​ 因为cacheEnabled 的取值默认就为true,所以这一步可以省略不配置。为true 代表开启二级缓存; 为false 代表不开启二级缓存。

<!--需要配置延迟加载策略-->
<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>   		 

​ 第二步:让当前的映射文件支持二级缓存(在UserDao.xml中配置)

​ 标签表示当前这个mapper 映射将使用二级缓存,区分的标准就看mapper 的namespace 值。

<mapper namespace="com.cyannote.dao.UserDao">
    <cache/>
</mapper>

​ 第三步:让当前的操作支持二级缓存(在select标签中配置)

​ 将UserDao.xml 映射文件中的标签中设置useCache=”true”代表当前这个statement 要使用二级缓存,如果不使用二级缓存可以设置为false。

注意:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。

<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="com.cyannote.domain.User" useCache="true">
    select * from user where id = #{uid}
</select>

​ 二级缓存结构图
在这里插入图片描述
​ 经过测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。

​ 但是查询到的2个对象不一致,原理是二级缓存中存放的是对象的散装数据,每次查询的时候需要重新封装实体对象。

考虑二级缓存的应用场景:

​ 适应放置到二级缓存的数据:经常不会发生变化的数据,例如地区编码

​ 不适合放置到二级缓存的数据:经常变化的数据, 财务数据

6.mybatis注解开发

加载注解依赖(pom.xml)

		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

配置映射(SqlMapConfig.xml)

<!-- 指定带有注解的dao接口所在位置 -->
    <mappers>
        <mapper class="com.cyannote.dao.UserDao"></mapper>
    </mappers>

6.1 mybatis的注解说明

​ @Insert:实现新增

​ @Update:实现更新

​ @Delete:实现删除

​ @Select:实现查询

​ @Result:实现结果集封装

​ @Results:可以与@Result一起使用,封装多个结果集

​ @One:实现一对一结果集封装

​ @Many:实现一对多结果集封装

​ @SelectProvider: 实现动态SQL映射

6.2 使用注解开发

使用注解进行CRUD操作

 	//    查询所有
    @Select(value = "select * from account")
    List<Account> findAll();

    //    增加一条记录
    @Insert(value = "insert into account (uid,money) values (#{uid},#{money})")
    void save(Account account);

    //    删除一条记录
    @Delete(value = "delete from account where id = #{id}")
    void delete(int id);

    //    修改一条记录
    @Update(value = "update account set uid = #{uid},money = #{money} where id= #{id}")
    void update(Account account);

使用注解实现复杂关系映射开发

@one:多对一和一对一

 @Select(value = "SELECT * from account")
 @Results(id = "AccountUser", value = {
            @Result(id = true, property = "id", column = "id"),
            @Result(property = "uid", column = "uid"),
            @Result(property = "money", column = "money"),
            @Result(property = "user", column = "uid", one = @One(select = "com.cyannote.dao.UserDao.findByUId"))
    })
    List<Account> findAccountUser();

@many:一对多和多对多

@Select(value = "select * from user")
@Results(id = "UserAccount",value = {
            @Result(id = true , property = "id" , column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "sex" , column = "sex"),
            @Result(property = "birthday" , column = "birthday"),
            @Result(property = "address" , column = "address"),
            @Result(property = "accounts",column = "id",many = @Many(select = "com.cyannote.dao.AccountDao.findById"))
    })
    List<User> findUserAccount();

使用联合查询的SQL语句

@Select(value = "SELECT u.*,a.id aid,a.UID,a.MONEY FROM USER u,account a WHERE a.uid = u.id")
    @Results(id = "AccountUser2",value = {
            @Result(id = true,property = "id",column = "aid"),
            @Result(property = "uid",column = "uid"),
            @Result(property = "money",column = "money"),
            @Result(property = "user.id",column = "id"),
            @Result(property = "user.username",column = "username"),
            @Result(property = "user.sex",column = "sex"),
            @Result(property = "user.birthday",column = "birthday"),
            @Result(property = "user.address",column = "address"),
    })
    List<Account> findAccountUser2();

使用注解配置二级缓存

第一步:配置SqlMapConfig.xml

<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

第二步:配置UserDao.xml

@CacheNamespace(blocking = true) // 使用二级缓存
public interface UserDao {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值