SSM Mybatis

mybatis

mybatis简介

在这里插入图片描述

持久化

在这里插入图片描述

持久层

Dao Service Controller

  • 完成持久化动作的代码块
  • 层界限十分明显

特点

在这里插入图片描述

crud这里就不写了 详情看代码或者配置文件

万能的map

  • map传递参数,在sql中取出key值即可
  • 对象传递参数,在sql中取出对象的属性即可
  • 只有一个基本类型参数的情况下,可以直接在sql中取到
  • 多个参数用map或者注解

模糊查询

  • Java代码执行时 传递通配符

List userList = mapper.getuserLike("%李%");

  • 在sql拼接的时候使用通配符

select * from user where name like “%{value}%”

优化

核心配置文件mybatis-config.xml

configuration(配置) 下方的顺序也是配置文件的写入顺序

环境配置

在这里插入图片描述

属性优化
  • db.properties

  • log4j.properties

引入配置

<properties resourse="db.properties">

定义一些数据库的配置文件 优先使用db.properties的东西 没有的话在自定义的配置文件中寻找

<properties resource="db.properties">
     <property name="username" value="root"/>
     <property name="pwd" value="11111"/>
</properties>
别名优化typeAliases

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

也可以使用包名

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

也可以在实体类上加注解

@Alias("")

设置setting
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
mapper映射器
  • resource 相对于类路径的资源引用 没有限制 引用xml文件
  • class 使用映射器接口实现类的完全限定类名 引用到mapper文件
    • 接口和他的mapper配置文件必须同名
    • 接口可他的mapper配置文件必须在一个包下
<mappers>
	<mapper resource="">
</mappers>
  • package 将包内的映射器接口实现全部注册为映射器 引用到dao包
<mappers>
	<package name="">
</mappers>
ResultMap

解决属性名和字段名不一致的问题(数据库的字段和实体类下的属性名不一致)

  • 起别名 pwd as password

resultType 具体的类型

resultMap 结果集映射

在这里插入图片描述

日志工厂

setting 配置 logImpl

在mybatis中具体在那个日志中输出 由setting决定

主要使用的日志工具

在这里插入图片描述

一对多

javaType 用来指定实体类中属性的类型 int arrayList

ofType 用来指定映射到List或者集合中的pojo类型 泛型中的约束类型 泛型中尖括号里的东西

按照查询嵌套处理就像sql中的子查询

按照结果进行嵌套处理就像sql中的联表查询

表数据关联        集合 collection
use how2java;
delete from category_;
INSERT INTO category_ VALUES (1,'category1');
INSERT INTO category_ VALUES (2,'category2');
delete from product_;
INSERT INTO product_ VALUES (1,'product a', 88.88, 1);
INSERT INTO product_ VALUES (2,'product b', 88.88, 1);
INSERT INTO product_ VALUES (3,'product c', 88.88, 1);
INSERT INTO product_ VALUES (4,'product x', 88.88, 2);
INSERT INTO product_ VALUES (5,'product y', 88.88, 2);
INSERT INTO product_ VALUES (6,'product z', 88.88, 2);

categoey中增加product 集合
public class Category {
    private int id;
    private String name;
    List<Product> products;
	......    
}

xml
         <resultMap type="Category" id="categoryBean">
            <id column="cid" property="id" />
            <result column="cname" property="name" />
     
            <!-- 一对多的关系 -->
            <!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
            <collection property="products" ofType="Product">
                <id column="pid" property="id" />
                <result column="pname" property="name" />
                <result column="price" property="price" />
            </collection>
        </resultMap>
     
        <!-- 关联查询分类和产品表 -->
        <select id="listCategory" resultMap="categoryBean">
            select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname' from category_ c left join product_ p on c.id = p.cid
        </select> 

在这里插入图片描述

在这里插入图片描述

多对一

关联 association

这是多对一查询效果,查询出所有的产品,同时对于每个产品,还能看到其所对应的分类
为Product增加category属性
public class Product {
    private int id;
    private String name;
    private float price;
    private Category category;
	.....
} 

xml
        <resultMap type="Product" id="productBean">
            <id column="pid" property="id" />
            <result column="pname" property="name" />
            <result column="price" property="price" />
     
            <!-- 多对一的关系 -->
            <!-- property: 指的是属性名称, javaType:指的是属性的类型 -->
            <association property="category" javaType="Category">
                <id column="cid" property="id"/>
                <result column="cname" property="name"/>
            </association>
        </resultMap>
     
        <!-- 根据id查询Product, 关联将Orders查询出来 -->
        <select id="listProduct" resultMap="productBean">
            select c.*, p.*, c.id 'cid', p.id 'pid', c.name 'cname', p.name 'pname' from category_ c left join product_ p on c.id = p.cid
        </select>   

在这里插入图片描述

起别名的时候as可以省略

在这里插入图片描述

小结

按照查询进行嵌套处理就像SQL中的子查询
按照结果进行嵌套处理就像SQL中的联表查询

动态sql

if

<select id="listProduct" resultType="Product">
	select * from product_
	<if test="name!=null">
		where name like concat('%',#{name},'%')
	</if>		 	
</select>
Product的字段比较多的话,为了应付各个字段的查询,
上面语句的意思没有传参数查询所有,传了参数模糊查询

where

如果要进行多条件判断,就会写成这样:
<select id="listProduct" resultType="Product">
	select * from product_
	<where>
		<if test="name!=null">
			and name like concat('%',#{name},'%')
		</if>		 	
		<if test="price!=null and price!=0">
			and price > #{price}
		</if>	
	</where>	 	
</select>
<where>标签会进行自动判断
如果任何条件都不成立,那么就在sql语句里就不会出现where关键字
如果有任何条件成立,会自动去掉多出来的 and 或者 or。

set

与where标签类似的,在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签:
  <set>
     	<if test="name != null">name=#{name},</if>
     	<if test="price != null">price=#{price}</if>
    </set>

trim

trim 用来定制想要的功能,比如where标签就可以用
<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ... 
</trim>
来替换

set标签就可以用 
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>
来替换
运行set标签中的代码,其效果是一样的。

choose

Mybatis里面没有else标签,但是可以使用when otherwise标签来达到这样的效果。
<select id="listProduct" resultType="Product">
	  SELECT * FROM product_ 
	  <where>
	  	<choose>
		  <when test="name != null">
		    and name like concat('%',#{name},'%')
		  </when>			  
		  <when test="price !=null and price != 0">
		    and price > #{price}
		  </when>			  		
	  	  <otherwise>
	  	  	and id >1
	  	  </otherwise>
	  	</choose>
	  </where>
</select>
其作用是: 提供了任何条件,就进行条件查询,否则就使用id>1这个条件。

foreach

 SELECT * FROM product_ 
 	WHERE ID in
			<foreach item="item" index="index" collection="list"
    			open="(" separator="," close=")">
      		             #{item}
			</foreach>
foreach标签通常用于in 这样的语法里
查询指定数据

bind标签

bind标签就像是再做一次字符串拼接,方便后续使用
<mapper namespace="com.how2java.pojo">
        <!-- 本来的模糊查询方式 -->
<!--         <select id="listProduct" resultType="Product"> -->
<!--             select * from   product_  where name like concat('%',#{0},'%') -->
<!--         </select> -->
             
        <select id="listProduct" resultType="Product">
            <bind name="likename" value="'%' + name + '%'" />
            select * from   product_  where name like #{likename}
        </select>
         
    </mapper>
注解
mapper接口
public interface CategoryMapper {
    @Insert(" insert into category_ ( name ) values (#{name}) ") 
    public int add(Category category); 
    
    @Delete(" delete from category_ where id= #{id} ") 
    public void delete(int id); 
        
    @Select("select * from category_ where id= #{id} ") 
    public Category get(int id); 
      
    @Update("update category_ set name=#{name} where id=#{id} ") 
    public int update(Category category);  
        
    @Select(" select * from category_ ") 
    public List<Category> list(); 
    }
    
接口中定义的成员变量,默认是用public static final 修饰的
接口中定义的方法,默认是用public abstract 修饰的
接口中定义的内部类,默认是用public static修饰的
关于@Param()注解
方法存在多个参数,所有的参数前面必须加上 @Param("id")注解
  • 基本类型的参数或者String类型。需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略 建议都加上
  • 我们在sql中引用的就是我们这里的@Param()中设定的属性名

#{} 和${}区别

${}不安全

在这里插入图片描述

分页

狂神说

#语法
SELECT * FROM table LIMIT stratIndex,pageSize
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.
#如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
#换句话说,LIMIT n 等价于 LIMIT 0,n。

    //分页
    List<User> getUserByLimit(Map<String,Integer> map);

    //分页2
    List<User> getUserByRowBounds();
    <!--分页-->
    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from  mybatis.user limit #{startIndex},#{pageSize}
    </select>

    <!--分页2-->
    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from  mybatis.user
    </select>

    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //RowBounds实现
        RowBounds rowBounds = new RowBounds(1, 2);

        //通过Java代码层面实现分页
        List<User> userList = sqlSession.selectList("
        com.kuang.dao.UserMapper.getUserByRowBounds",null,rowBounds);

        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();
    }

    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("startIndex",1);
        map.put("pageSize",2);

        List<User> userList =  mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();
    }

原理图
  1. 应用程序找Mybatis要数据
  2. mybatis从数据库中找来数据
    2.1 通过mybatis-config.xml 定位哪个数据库
    2.2 通过Category.xml执行对应的select语句
    2.3 基于Category.xml把返回的数据库记录封装在Category对象中
    2.4 把多个Category对象装在一个Category集合中
  3. 返回一个Category集合

基本原理图

mybayis执行流程

在这里插入图片描述

源码流程

Resourse获取了一个流,通过构造器build,build调用了build方法,build方法调用xmlConfigBuilder类,解析了流环境和配置文件,传给了configuration,然后sqlsession实例化,创建executor执行器,执行了事务、缓存、查询的一些栈、流的关闭

缓存
  • 一级缓存 缓存session 第一次将数据存在缓存中,第二次直接取缓存中取,在数据没有发生改变的情况下

SQL session级别的缓存 默认开启 提高查询效率 也称为本地缓存

  • 二级缓存 namespace级别的缓存 需要手动开启和配置 全局缓存(一个命名空间对应一个二级缓存)
  • 为了提高扩展性 mybatis增加了缓存接口Cache 所有mapper共享

一级缓存失效的四种情况

一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求

  • sqlsession 不同 每个sqlSession中的缓存相互独立
  • sqlSession相同,查询条件不同 当前缓存中,不存在这个数据
  • sqlSession相同,两次查询之间执行了增删改操作! 因为增删改操作可能会对当前数据产生影响
  • sqlSession相同,手动清除一级缓存 一级缓存就是一个map

二级缓存的工作机制

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;

  • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一

    级缓存中的数据被保存到二级缓存中;

  • 新的会话查询信息,就可以从二级缓存中获取内容;

  • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

结论

  • 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
  • 查出的数据都会被默认先放在一级缓存中
  • 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中

第三方缓存Ehcache

配置文件

引入mybatis-EhCache包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatisehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>

<mapper namespace = “org.acme.FooMapper” >
	<cache type = “org.mybatis.caches.ehcache.EhcacheCache” />
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统宕机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->

</ehcache>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值