Mybatis
目录
什么是Mybatis ?
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
Mybatis 如何安装?
要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于 classpath 中即可。
如果使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Mybatis 功能架构?
1. API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
2. 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
3. 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
MyBatis的优缺点
优点:
• 简单易学:比传统JDBC减少61%的代码量,本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
• 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
• 解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
• 提供映射标签,支持对象与数据库的orm字段关系映射
• 提供对象关系映射标签,支持对象关系组建维护
• 提供xml标签,支持编写动态sql。
缺点:
• 编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
• SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
• 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
• 二级缓存机制不佳
Mybatis使用
MyBatis基本要素:
1. configuration.xml 全局配置文件
2. xml映射文件(mapper)—实体类
3.SqlSession接口
核心配置文件:
<configuration>
<!-- 类型别名设置 -->
<typeAliases>
<typeAlias alias="Stu" type="com.it.entity.Stu"/>
</typeAliases>
<mappers>
<!-- 对应实体类的映射文件路径 -->
<mapper resource="com/it/entity/Stu.xml"/>
</mappers>
</configuration>
xml映射文件
<mapper namespace="com.majing.learning.mybatis.dao.UserDao">
<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into user(name,password,age) values(#{name},#{password},#{age})
</insert>
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="user" >
update user set name = ’ ${name}’, password = #{password}, age = #{age} where id = #{id}
</update>
</mapper>
注意:
$ {name}和# {password}之间的差别
自增字段的插入
在数据库里面经常性的会给数据库表设置一个自增长的列作为主键,如果我们操作数据库后希望能够获取这个主键该怎么弄呢?正如上面所述,如果是支持自增长的数据库,如mysql数据库,那么只需要设置useGeneratedKeys和keyProperties属性便可以了。
但是对于不支持自增长的数据库(如oracle)该怎么办呢?
<selectKey resultType="java.lang.Long" keyProperty="id" order="BEFORE">
select seq_T_RB_CONTRACT_INFO.nextval as id from dual
</selectKey>
查询
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中
<resultMap type="" id="">
<!– id property属性对应javabean的属性名,column对应数据库表的列名(这样,当javabean的属性与数据库对应表的列名不一致的时候,就能通过指定这个保持正常映射了) -->
<id property="" column=""/>
<!-- result与id相比, 对应普通属性 -->
<result property="" column=""/>
<!-- constructor对应javabean中的构造方法 -->
<constructor>
<!-- idArg 对应构造方法中的id参数 -->
<idArg column=""/>
<!-- arg 对应构造方法中的普通参数 -->
<arg column=""/>
</constructor>
<!-- collection,对应javabean中容器类型, 是实现一对多的关键
property 为javabean中容器对应字段名
column 为体现在数据库中列名
ofType 就是指定javabean中容器指定的类型 -->
<collection property="" column="" ofType=""></collection>
<!-- association 为关联关系,是实现N对一的关键。
property 为javabean中容器对应字段名
column 为体现在数据库中列名
javaType 指定关联的类型 -->
<association property="" column="" javaType=""></association>
</resultMap>
查询示例
<mapper namespace="twm.mybatisdemo.mapper.OrderMapper">
<!-- 定义类型映射 -->
<resultMap type="Order" id="OrderMap">
<!-- 订单表属性 -->
<id column="id" property="id" />
<result column="orderno" property="orderno" />
<result column="create_time" property="create_time" />
<result column="create_userid" property="create_userid" />
<!-- 关联的用户信息 -->
<!-- association用于关联查询:
property指属性,javaType是要映射的对象的类型。 -->
<association property="user" javaType="User">
<result column="username" property="username" />
<result column="address" property="address" />
<result column="cellphone" property="cellphone" />
</association>
</resultMap>
<select id="getList" resultMap="OrderMap">
SELECT `order`.*,`user`.username,`user`.address,`user`.cellphone FROM `order` ,`user` WHERE `order`.create_userid=`user`.id </select>
</mapper>
集合嵌套查询
集合的嵌套查询(select)
集合的嵌套结果(resultMap)
批量插入
Oracle数据库
方法1:
insert into user_info(id,uname,unumber)
select id ,uname,unumber from (
<foreach collection="users" item="emp" separator=" union all ">
select #{emp.id} id,#{emp.uname} uname,#{emp.unumber} unumber from dual
</foreach>
) A
方法2:
INSERT ALL
<foreach collection="users" item="emp" >
into user_info(id,uname,unumber)
values( #{emp.id} ,#{emp.uname} ,#{emp.unumber} )
</foreach>
SELECT 1 FROM DUAL
语法
insert all
into table(c1,c2,c3) values(a,b,c)
into table2(d1,d2,d3) values(a,b,c)
…
select a,b,c from table2
Mybatis 缓存
Mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
一级缓存
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
一级缓存的应用:
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
service{
//开始执行时,开启事务,创建SqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
//方法结束,sqlSession关闭
}
如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
一级缓存默认是开启的,可以select 中添加flushCache=“true” 来关闭一级缓存
二级缓存
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。
开启二级缓存:
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。
mapper中加入<cache/>
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
Oracle与mysql常用语句区别
Oracle 关联更新
-- 方法1
update customers a -- 使用别名
set (city_name,customer_type)=(select b.city_name,b.customer_type
from tmp_cust_city b
where b.customer_id=a.customer_id)
where exists (select 1
from tmp_cust_city b
where b.customer_id=a.customer_id);
--方法2
MERGE INTO table_name alias1
USING (table|view|sub_query) alias2
ON (join condition)
WHEN MATCHED THEN
UPDATE table_name
SET col1 = col_val1,
col2 = col2_val
WHEN NOT MATCHED THEN
INSERT (column_list) VALUES (column_values);
方法1:
update xcs_user_credit_score a1,xcs_user_credit_score a2
set a1.user_currday_score=a1.user_currday_increment_score+a2.user_currday_score
where a1.pt_day='2017-09-20' and a2.pt_day='2017-09-19'
and a1.uid=a2.uid;
方法2 :
update xcs_user_credit_score a1
inner join xcs_user_credit_score a2
on a1.uid=a2.uid
set a1.user_currday_score=a1.user_currday_increment_score+a2.user_currday_score
where a1.pt_day='2017-09-20' and a2.pt_day='2017-09-19'