mybatis

mybatis

概述

原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了 Google Code,随着开发团队转投Google Code 旗下, iBatis3.x正式更名为MyBatis。 MyBatis 是一款优秀的持久层框架。 MyBatis 避免了几乎所有的 JDBC 代码手动设置参数以及手动获取结果集的操 作。 Mybatis 将基本的 JDBC 常用接口封装,对外提供操作即可. MyBatis 可以使用 XML 或注解来配置和映射,将数据库中的记录映射成 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象),是一种 ORM(ORM Object Relational Mapping 对象关系映射)实现. 它支持动态 SQL 以及数据缓存. Mybatis 中文官网 https://mybatis.org/mybatis-3/zh_CN/index.html

mybatis使用xml或者注解的方式,将数据库记录映射到java对象中,是一种orm(对象关系映射)实现.支持动态sql以及数据缓存(一级缓存 和二级缓存)

配置的文件:1.mybatis.xml 全局配置 2.sql映射文件 xxxMapper.xml文件

mybatis对jdbc原生的接口和类进行封装,sqlsessionfactory读取配置文件,用来穿件sqlsession对象

sqlsession对象与数据库连接

mybatis搭建

1.现在数据库创建一张表和一个项目 创建一个实体类

2.导入mybatis和mysql的jar包

创建mybatis核心配置文件

事务管理方式:就是一次对数据库操作过程中,执行多条sql的管理 把所有的操作都成功执行后,在提交事务,让数据库最终执行本次提交的所有sql

数据库连接池:频繁的创建销毁与数据库的连接对象是比较占用空间和时间的,可以在池子中默认创建若干个连接对象,有请求使用时,直接从连接池中取出一个对象,用完就还回去,这样就减少了创建和销毁的时间开销

参数传递

单个参数直接传递 Admin selectAdmins(int id);

多个参数使用@Param(“id”)绑定 Admin selectAdmins(@Param(“account”)String account, @Param(“password”)String password);

<select id="selectAdmins" resultType="Admin">
select id, account, password from admin where account= #{account} and password=#{password}
</select>

新增

如果传入一个复杂的对象,就需要使用 parameterType 参数进行类型定义,例如: void insertAdmin(Admin admin)

<insert id="insertAdmin" parameterType="Admin" parameterType="Admin" useGeneratedKeys="true" keyProperty="id" keyColumn="id" >
insert into admin(id, account, password)
values (#{id}, #{account}, #{password})
</insert>

 useGeneratedKeys="true" 取出数据库生成的主键
 keyProperty="id" keyColumn="id" 表示映射关系

#{ } 一般用于向sql中传值用,是占位的,预编译的 ,比较安全.

${ }是将值直接拼接在sql中,一般不用于向sql中传值用,一般用于动态传递列名 例如排序 order by 后边的列名是变化的

修改

 <update id="updateadmin" parameterType="Admin">
        update admin set account=#{account},gender=#{gender} where id=#{id}
    </update>

删除

<delete id="deleteadmin" parameterType="int">
        delete from admin where id=#{id}
    </delete>

查询

<select id="findAdminById" parameterType="int" resultType="Admin">
    select * from admin where id = #{id}
</select>

结果处理

简单类型输出映射 返回简单基本类型

<select id="findadmincount" resultType="int">
    select count(*) from admin
</select>

System.out.println(adminDao.findadmincount());

对象映射

如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装 到POJO对象中.

1.如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开始全局 设置实现自动转换

2.也可以在sql语句中给查询到的结果起别名 与属性名一致即可

<setting name="mapUnderscoreToCamelCase" value="true"/>  
<!--开启数据库与java属性名转换 例如user_name 转化为userName  -->
<select id="findAdmins" resultType="Admin">
    select id,account,password,gender,admin_age as userName from admin
</select>

特殊处理定义 resultMap

<resultMap id="adminmap" type="Admin">
    <id property="id" column="id"></id><!--映射主键-->
    <result property="account" column="account"></result>
    <result property="password" column="password"></result>
    <result property="gender" column="gender"></result>
</resultMap>

 <select id="findAdminById" parameterType="int" resultMap="adminmap">
        select * from admin where id = #{id}
    </select>

将查询到的column中的数据映射到Admin类中的property中

多表关联处理结果集

<!--自定义映射关系-->
<resultMap id="studentmap" type="student"> <!--最终返回student对象 将信息封装给学生对象-->
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <result column="name" property="name"></result>
    <result column="gender" property="gender"></result>
    <!--自动创建一个major对象,将专业的名字封装到专业对象中,把专业对象赋给学生对象-->
    <association property="major" javaType="Major">
        <result property="name" column="mname"></result>
    </association>
</resultMap>

<select id="findstudentbyid" parameterType="int" resultMap="studentmap">
    select s.id,s.num,s.name,s.gender,m.name mname from student s left join major  m on s.majorid=m.id where s.id=#{id}
</select>

需要将数据封装到内部的一个对象时 需要用到 选择查询到的数据赋给javatype类型的property属性,若此属性是对象 ,则可以赋给此对象内部的属性.

设置自动映射级别 autoMappingBehavior

指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。

NONE 完全关闭自动映射

PARTIAL 当查询没有嵌套查询时,会自动映射,一旦有嵌套查询就不自动映射

FULL 无论是否有嵌套查询都会自动影射

mybatis官方默认为PARTIAL

嵌套查询

<!--嵌套查询 把一个关联查询 分成了两个单表查询,先查询学生信息 ,然后通过学生专业外键查询关联的专业信息-->
<select id="findstudentbyid" parameterType="int" resultMap="studentmap">
    select s.id,s.num,s.name,s.gender,m.name mname from student s left join major  m on s.majorid=m.id where s.id=#{id}
</select>
<select id="findstudents" resultMap="studentmap">
    select s.id,s.num,s.name,s.gender,m.name mname from student s left join major  m on s.majorid=m.id
</select>

<resultMap id="findstudentbyid1" type="student" >
    <association property="major" select="findmajor" column="majorid" javaType="Major"></association>
</resultMap>
<select id="findstudentbyid1" parameterType="int"  resultMap="findstudentbyid1">
    select s.id,s.num,s.name,s.gender,s.majorid mname from student s where s.id=#{id}
</select>
<select id="findmajor" parameterType="int" resultType="major">
    select name from major where id=#{majorid}
</select>

当需要返回多个对象时候 需用到 返回一个有student对象信息的集合list

<resultMap id="findmajor" type="major">
    <id javaType="int" column="id"></id>
    <result column="name" property="name"></result>
    <collection property="students" javaType="list" ofType="student">
        <result column="name" property="name"></result>
        <result column="gender" property="gender"></result>
    </collection>
</resultMap>

模糊查询

1.select * from student where name like ‘${name}%’ 字符串拼接

2.select * from student where name like concat(#{name},‘%’) 使用数据库函数连接字符串

3.可以直接将查询的值加入% 如:张% 直接传给占位符#{name}

注解方式

常用注解标签

@Insert : 插入 sql , 和 xml insert sql 语法完全一样

@Select : 查询 sql, 和 xml select sql 语法完全一样

@Update : 更新 sql, 和 xml update sql 语法完全一样

@Delete : 删除 sql, 和 xml delete sql 语法完全一样

动态sql—>标签

MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么 的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理 这种痛苦。 MyBatis 中用于实现动态 SQL 的元素主要有: If where trim set choose (when, otherwise) foreach

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

if test=“条件表达式” 条件表达式成立则会将if标签内部的sql语句拼接

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where判断内部if标签 如果有一个返回true,会自动添加一个where关键字 还会去除where后面的多余关键字

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

标签可以让我们添加一个指定的prefix前缀关键字,去除一个指定的prefixOverrides关键字

set标签 可以动态增加set关键字 还可以去除逗号

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

item=“a” 定义一个变量,接受每次循环中获得的元素

collection=“list|array” 循环的集合类型 list-集合 array-数组

open=“(” 循环开始的一个符号

close=“)” 循环结束的一个符号

separator=“,” 每次循环后的一个分隔符号

index 循环时生成的索引

xml中的特殊符号处理

解决方法

1:可以用转义字符 在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。

2.<![CDATA[ 特殊符号 ]]>是 XML 语法。在 CDATA 内部的所有内容都会被解析器忽略。

mybatis缓存

为什么使用缓存 ?

缓存(cache)的作用是为了减去数据库的压力,提高查询性能。缓存实现的 原理是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存) 中,当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库 执行 select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。

将第一次查询mysql的数据存储在一个java对象中,不销毁,下次查询时,直接从java对象中获取,不用连接数据库,减轻数据库的压力

那些数据适合放在缓存中?

1.修改较少的

2.访问量巨大,短时间内访问量非常大的

3.结构简单的数据 例如点赞 也是操作频繁的的

一级缓存

Mybatis 有一级缓存和二级缓存。一级缓存的作用域是同一个 SqlSession, 在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库 中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查 询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的一级缓存 也就不存在了。Mybatis默认开启一级缓存. 在同一个sqlsession中,再次查询相同内容 会从一级缓存中查询 不会查询数据库

Mybatis 对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓 存,一级缓存只是相对于同一个 SqlSession 而言。 所以在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调 用一个 Mapper 方法,往往只执行一次 SQL,因为使用 SelSession 第一次查询 后,MyBatis 会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新, 并且缓存没有超时的情况下,SqlSession 都会取出当前缓存的数据,而不会再 次发送 SQL 到数据库。

1.执行完删除 修改 新增操作后 会清空一哦缓存数据

2.强制清空一级缓存

3.sqlsession.close() 关闭连接对象

二级缓存

二级缓存是多个 SqlSession 共享的,其作用域是同一个 namespace,不同的 sqlSession 两次执行相同 namespace 下的 sql 语句且向 sql 中传递参数也相同 即最终执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存 (内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。 Mybatis 默认没有开启二级缓存需要在 setting 全局参数中配置开启二级缓存

二级缓存是 SqlSessionFactory 级别的,根据 mapper 的 namespace 划分 区域的,相同 namespace 的 mapper 查询的数据缓存在同一个区域,如果使 用 mapper 代理方法每个 mapper 的 namespace 都不同,此时可以理解为二 级缓存区域是根据 mapper 划分。 每次查询会先从缓存区域查找,如果找不到则从数据库查询,并将查询到数 据写入缓存。Mybatis 内部存储缓存使用一个 HashMap,key 为 hashCode+sqlId+Sql 语句。value 为从查询出来映射生成的 java 对象。 sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存

二级缓存时sqlsessionfactory级别(sqlsessionfactory对象只有一个,创建后就不关闭,多个sqlsession共享一个sqlsessionfactory)

使用需要配置

第一步:启用二级缓存 在 SqlMapperConfig.xml 中启用二级缓存,如下代码所示,当 cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。

第二步:对象序列化 将所有的 POJO 类实现序列化接口 Java.io. Serializable。

第三步:配置映射文件 在 Mapper 映射文件中添加 ,表示此 mapper 开启二级缓存。 当 SqlSeesion 关闭时,会将数据存入到二级缓存.

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

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

默认的清除策略是 LRU。

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

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

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值