您的位置:首页 > 其它

mybatis相关知识点

2017-07-23 16:14 330 查看

映射文件的相关属性

namespace命名空间

作用: 对sql进行分类化管理,理解sql隔离

注意:使用mapper代理方法开发,namespace有特殊重要的作用

<!-- 需求:通过id查询用户表的记录 -->
<select id="findUserById" parameterType="int" resultType="com.chaychan.mybatis.po.User">
SELECT * FROM USER WHERE id=#{value}
</select>


上面代码的解释

id:标识映射文件中的 sql,将sql语句封装到mappedStatement对象中,所以将id称为statement的id

parameterType:指定输入 参数的类型,这里指定int型

resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。

“#{}” 表示一个占位符号

“#{id}” 其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称.

${}的使用

<!-- 通过用户的名称模糊搜索用户,搜索的结果可能有多条   resultType指定就是单条记录所映射的java对象
${}表示拼接sql串,将接收到的内容不加任何修饰拼接在sql中
使用${}拼接sql,会引起sql注入,比如传入的字符串是sql指令(有一定的风险)
${value}:接收输入的内容,如果传入的类型是简单类型,${}中只能用value
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.chaychan.mybatis.po.User">
SELECT * FROM USER WHERE USERNAME LIKE '%${value}%';
</select>


以上的模糊搜索会引起sql注入,所以还是使用下面的代码

<select id="findUserByName" parameterType="java.lang.String" resultType="com.chaychan.mybatis.po.User">
<!-- SELECT * FROM USER WHERE USERNAME LIKE '%${value}%';
为了防止sql注入,所以采用下面的方式-->
SELECT * FROM USER WHERE USERNAME LIKE #{value};
</select>


代码中传入参数替代占位符

List<User> list = sqlSession.selectList("test.findUserByName","%小明%");


插入数据

<!-- 添加用户
parameterType:指定输入参数的类型为pojo(包含用户信息)
#{}指定pojo的属性名,就可以接收到相应的属性值,mybatis是通过OGNL获取属性值
-->
<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
insert into user(username,birthday,sex,address)
value(#{username},#{birthday},#{sex},#{address})
</insert>


插入数据后拿到自增长的主键的值

<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
value(#{username},#{birthday},#{sex},#{address})
</insert>


以上代码的解释

SELECT LAST_INSERT_ID(): 得到刚 insert进去记录的主键值,只适用于自增长主键

keyProperty: 将查询到的主键值设置到parameterType对应的对象的哪个属性中,上述代码是将主键值设置到User对象的id属性中

order: SELECT LAST_INSERT_ID()的执行顺序,相对于insert来说的顺序

resultType: 指定SELECT LAST_INSERT_ID()的结果类型

在插入数据之前通过mysql的uuid()生成主键,然后再将其作为主键值插入

使用mysql的uuid()生成主键

执行过程:

首先通过uuid()得到主键,将主键设置到user对象的id属性中

其次在insert执行时,从user对象中取出id属性值

<insert id="insertUser" parameterType="com.chaychan.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
value(#{id},#{username},#{birthday},#{sex},#{address})
</insert>


mapper的编写

程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类的代理对象

开发规范:

1.在mapper.xml中的namespace等于mapper接口的类的全路径

<mapper namespace="com.chaychan.mybatis.mapper.UserMapper">


2.mapper.java接口中的方法名要和mapper.xml中statement的id一致

3.mapper.java接口中的方法的输入参数类型要和mapper.xml中statement的parameterType指定的类型一致

4.mapper.java接口中的方法返回值类型要和mapper.xml中statement的resultType指定的类型一致

如mapper.xml中代码:

<select id="findUserById" parameterType="int" resultType="com.chaychan.mybatis.po.User">
SELECT * FROM USER WHERE id=#{value}
</select>


mapper接口中的方法:

/**根据id查找用户信息*/
public User findUserById(int id) throws Exception;


定义别名

单个别名的定义

SqlMapConfig.xml中配置User对象全路径对应的别名为user

<!-- 定义别名 -->
<typeAliases>
<!--单个别名的定义-->
<typeAlias type="com.chaychan.mybatis.po.User" alias="user"/>
</typeAliases>


mapper.xml中只需使用别名user:

<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{value}
</select>


批量别名的定义

SqlMapConfig.xml中配置要包名

<!-- 定义别名 -->
<typeAliases>
<!-- 批量别名的定义
指定包名,mybatis就会自动扫描包中的po类,自动定义别名,别名为类名(首字母大小写都可以)
-->
<package name="com.chaychan.mybatis.po"/>

</typeAliases>


加载映射文件

单个加载映射文件,通过mapper接口加载映射文件

批量加载映射文件,指定mapper接口所在的包名,mybatis会自动加载mapper接口

两种方法都要遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下

<!-- 加载 映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<!-- <mapper resource="mapper/UserMapper.xml"/> -->
<!-- 单个加载映射文件,通过mapper接口加载映射文件
遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下
-->
<!-- <mapper class="com.chaychan.mybatis.mapper.UserMapper"/> -->

<!--
批量加载映射文件
指定mapper接口所在的包名,mybatis会自动加载mapper接口
遵循一定的规范:需要将mapper接口的类名和mapper.xml映射文件名保持一致,且放在同一个目录下
-->
<package name="com.chaychan.mybatis.mapper"/>
</mappers>


reusltMap入门

<!-- 定义resultMap
将SELECT id id_,username username_ FROM USER 和User类中的属性作一个映射关系

type:resultMap最终映射的java对象类型,可以使用别名
id:对resultMap的唯一标识
-->
<resultMap type="user" id="userResultMap">
<!-- id表示查询结果集中唯一标识
column:查询出来的列名
property:type指定的pojo类型中的属性名
最终resultMap对column和property作一个映射关系 (对应关系)
-->
<id column="id_" property="id"/>
<!--
result:对普通名映射定义
column:查询出来的列名
property:type指定的pojo类型中的属性名
最终resultMap对column和property作一个映射关系 (对应关系)
-->
<result column="username_" property="username"/>

</resultMap>

<!-- 使用resultMap进行输出映射
resultMap:指定定义的resultMap的id,如果这个resultMap在其它的mapper文件,前边需要加namespace
-->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT id id_,username username_ FROM USER WHERE id=#{value}
</select>


定义sql片段

<!-- 定义sql片段
id:sql片段的唯 一标识

经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高
在sql片段中不要包括 where
-->
<sql id="user_query_where">
<if test="userCustom != null">
<if test="userCustom.sex != null and userCustom.sex != ''">
and sex = #{userCustom.sex}
</if>
<if test="userCustom.username != null and userCustom.username != ''">
and username like '%${userCustom.username}%'
</if>
</if>
</sql>


引用sql片段

<select id="findUserList" parameterType="userQueryVo" resultType="userCustom">
select * from user
<where>
<include refid="user_query_where" />
</where>
</select>


foreach的使用

<if test="ids != null">
<!-- 使用 foreach遍历传入ids
使用实现下边的sql拼接:
AND (id=1 OR id=10 OR id=16)
-->
<foreach collection="ids" item="item_id"
open="AND (" close=")" separator="OR">

id=#{item_id}

</foreach>

<!-- 使用实现下边的sql拼接:
AND id in(1,10,16)
-->
<foreach collection="ids" item="item_id"
open="AND id in(" close=")" separator=",">

#{item_id}

</foreach>
</if>


collection:指定输入对象中集合属性

item:每个遍历生成对象中

open:开始遍历时拼接的串

close:结束遍历时拼接的串

separator:遍历的两个对象中需要拼接的串

延迟加载

sqlConfig.xml中配置开启延迟加载

<!-- 全局配置参数,需要时再设置 -->
<settings>
<!-- 打开延迟加载 的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载即按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启二级缓存 -->
<!-- <setting name="cacheEnabled" value="true"/> -->
</settings>


定义一个延迟加载的mapper,如查询订单的时候,延迟加载用户信息,因为orders表中的user_id关联user表的id,当需要获取user对象的时候,就会执行延迟加载。

相当于两步:

1.先查询orders表获取到订单;

2.根据订单对象中user_id查找出相关的user对象

<!-- 延迟加载的resultMap -->
<resultMap type="com.chaychan.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<!--对订单信息进行映射配置 -->
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />

<!-- 实现对用户信息进行延迟加载
select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,如果findUserById不在本mapper中需要前边加namespace
column:订单信息中关联用户信息查询的列,是user_id
关联查询的sql理解为:
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username,
(SELECT sex FROM USER WHERE orders.user_id = user.id)sex
FROM orders
-->
<association property="user" javaType="com.chaychan.mybatis.po.User" column="user_id"
select="com.chaychan.mybatis.mapper.UserMapper.findUserById"
></association>

</resultMap>

<!-- 查询订单关联查询用户,用户信息需要延迟加载 -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
</select>


测试代码

List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();

for (Orders orders : list) {
User user = orders.getUser();
System.out.println(user);
}


当获取list的时候,控制台会输入查找orders表的sql语句,当orders对象调用getUser()方法的时候,控制台会输出根据id查找用户的sql语句。

查询缓存

一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据,不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的。

二级缓存是mapper级别的缓存,多个sqlSession去操作同一个Mapper中的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。

为什么要用缓存?如果缓存中有数据,就不用到数据库中去查找,大大提高系统的性能。

一级缓存的原理

例子:

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户的信息,如果没有,从数据查询用户信息。得到用户信息后,存储在以及缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),将清空sqlSession中的一级缓存,这样做的目的是为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户的信息,缓存中有,直接从缓存中获取用户信息。

二级缓存

mybatis默认开启一级缓存,如果要开启二级缓存,需要在xml中进行配置

原理:

sqlSession1去查询用户id为1的用户信息,查询到用户信息后将数据存储到二级缓存中。

sqlSession2去查询用户id为1的用户信息时,先去缓存中查找,如果存在则直接取出数据。

二级缓存和一级缓存的区别,二级缓存的范围更大,多个sqlSession可以共享一个Mapper的二级缓存区域,不如UserMapper有自己的二级缓存区域,其他mapper也有对应的二级缓存区域,按namespace区分。即每一个namespace的mapper有一个二级缓存区域。

如果两个mapper的namespace相同,这两个mapper执行sql查询到的数据将存在相同的二级缓存区域中。

整合ehcache

配置mapper中cache中的type为ehcache对cache接口的实现类

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>


导入mybatis-ehcache-1.0.2.jar,ehcache-core-2.6.5.jar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: