作者:longgangbai

以前用过ibatis2,但是听说ibatis3有较大的性能提升,而且设计也更合理,他不兼容ibatis2.尽管ibatis3还是beta10的状态,但还是打算直接使用ibatis3.0, 
ibatis3.0应该更简单高效.最近还自己写了个ibatis3.0与spring集成的bean,运行还正常,还自鸣得意了一番,但是当独立使用ibatis时,在事务管理这个方面还是出现不少问题,所以还是打算再认真研究一番ibatis3.0

1.SqlSessionFactory 
每个ibatis应用都应该只有一个SqlSessionFactory的实例对象,所以一般设置为static属性或者使用spring管理时返回singleton类型,与spring集成时其实也是写一个怎样构建SqlSessionFactory的Bean, 
构建SqlSessionFactory一般是SqlSessionFactoryBuild通过读取ibatis的配置文件而进行build的: 
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); 
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuild().build(reader);

配置文件SqlMapConfig.xml的一般结构(元素顺序不能变)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<settings>
<setting name="cacheEnabled" value="false" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="false" />
<setting name="useColumnLabel" value="true" />
<setting name="defaultExecutorType" value="SIMPLE" />
</settings>
<typeAliases>
<typeAlias alias="Person" type="test.Person"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<transactionManager type="jdbc">
<property name="" value="" />
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${user}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="sqlMappers/Person.xml" />
<mapper resource="sqlMappers/UserShop.xml" />
</mappers>
</configuration>

<settings />是配置ibatis的具体行为属性的,

<typeAliases />是为了将较长的module类名简化,在<mappers />里可以使用 
<environment />是配置transaction manager和connection pooling的 
<mappers />是sql语句的构造地方,一般每个module对应一个文件

2.SqlSession 
可以从SqlSessionFactory得到SqlSession: sessionFactory.openSession(); 
SqlSession是一切Sql相关数据库操作的中心,insert,select,update,delete... 
SqlSession不是线程安全的(也就是有状态的),所以它的作用域最好是在一个Thread下,每个Thread有自己的SqlSession对象实例,彼此不相关. 
Never keep references to a SqlSession instance in a static field or even an instance field of a class.  Never keep references to a 
SqlSession in any sort of managed scope, such as HttpSession of of the Servlet framework.

默认sessionFacory.openSession()拿到的SqlSession不是自动commit的,所以如果是更新操作必须自己执行session.commit() 
关闭SqlSession很重要,必须保证在线程结束时关闭这个SqlSession,可以在finally中 
session.close(); 
那跟Spring集成是怎样做到这一点的呢,因为dataSource是由spring管理的,所以他可以保证在一个Thread的每个方法中拿到的Connection是同一个对象, 
虽然每个方法从sessionFactory.openSession()拿到的SqlSession对象是不同的,但是sqlSession对象中的connection是相同的,所以spring就可以在service层的方法结束之前将这个connection commit跟close,这样就实现了事务控制. 
我们往往在dao层是一个方法对应一个sql语句的,不在这里控制事务,控制事务应该在service层, dao的每个方法拿到的sqlsession对象都是不相同的(尽管它的connection可能相同). 
那我们应该怎样在没有spring的情况下实现ibatis的事务控制呢?还要保持dao的结构,以保持能跟spring随时切换? 
看来ThreadLocal要派上用场了 
---占位----

3.讲完了SqlSession这个大头,再来说说具体的配置信息 
配置文件结构 
configuration 
    properties 
    settings 
    typeAliases 
    typeHandlers 
    objectFactory 
    plugins 
    environments 
       environment 
           transactionManager 
           dataSource 
    mappers 
       
4.ibatis可以配置多个environment环境 
供开发,测试,上线等切换 
但是一个SqlSessionFactory只能对应一个environment, 
也就是 one SqlSessionFactory per database

5.transactionManager 
There are two TransactionManager types (i.e. type=”?????”) that are included with iBATIS: 
    JDBC – This configuration simply makes use of the JDBC commit and rollback facilities directly.  It relies on the connection retrieved from the dataSource to manage the scope of the transaction.   
    MANAGED  – This configuration simply does nothing, quite literally.  It never commits, rolls back or closes a connection.  Instead, it lets the container manage the full lifecycle of the transaction (e.g. Spring or a JEE Application Server context).

6.dataSource的配置 
类型可使用UNPOOLED,POOLED,JNDI三种

7.接下来是重头戏mappers 
这里是我们直接写sql的地方,ibatis在这里也花了最多功夫,特别是关于select的mapper.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//ibatis.apache.org//DTD mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <mapper namespace="test.UserShop">
<insert ...> ... </insert>
<select ...> ... </select>
<update ...> ... </update>
<delete ...> ... </delete>
</mapper>

select 元素的所有的如下:

<select
id=""
parameterType=""
resultType=""
resultMap=""
flushCache=""
useCache=""
timeout=""
fetchSize=""
statementType=""
resultSetType="">

在Ibatis3中parameterMap已经不再使用。
(1).select 
<select id="getUser" parameterType="int" resultType="test.User"> 
       select * from user where userId = #{value} 
</select> 
注意#{value},resultType可以换成resultMap,这个resultMap就比较复杂了,也是最强大的工具,可以完成复杂的mapper(resultSet->object)

(2).insert,update,delete 
这几个操作都比较类似,返回的一般是受影响的行数. 
insert 可以返回auto_increament的值

<insert id="insertPerson" parameterType="Person"
useGeneratedKeys="true" keyProperty="userId">
insert into person(name,age) values(#{name},#{age})
</insert>

这样,传入的Person类对象的userId就会被set成auto_increament那个值.

(3).可以使用<sql id="columns">name,age</sql>构造可重用的sql片段 
这样就可以在那四个主要的元素里用<include refid="columns">引用这个常用sql片段

(4).resultMap很复杂,它可以处理一对一,一对多,多对多关系 
比如一个blog对应一个author, 一个blog对应多个post, 一个post对应多个comment 
resultMap的结构: 
resultMap 
    constructor (向java构造函数设置值) 
       idArg 
       arg 
    id (id result,同result) 
    result (字段映射注入) 
    association (一对一关系,它里面有自己的result映射) 
    collection  (一对多关系, 它里面有自己的result映射,和可能的collection) 
    discriminator

(5).association (一个Blog对应一个Author)

<resultMap id="blogResult" type="Blog">
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id" />
<result property="username" column="author_username" />
</associaton>
</resultMap>

当然association也可以使用 
<association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>

在Blog类定义里会有一个Author类字段,会自动装载数据 
private Author author;

(6).collection (一个Blog对应多个Post)

<resultMap id="blogResult" type="Blog">
<collection property="posts" column="blog_id" ofType="Post" javaType="ArrayList" resultMap="postResult" />
</resultMap>
collection也可以精简为
<collection property="posts" ofType="Post" resultMap="postResult" />
相就地,在Blog类定义里会有:
private List<Post> posts

8.cache

其实我是不打算在ibatis这层做cache的,一般cache还是在service层做. 
ibatis对于select才会进行cache,而我觉得这个时候cache没多大意义,因为多次請求相同的select語句(sql相同)而又没有进行表的相关update的情况并不多. 
但还是看看ibatis是怎样处理cache的 
要开启cache,需要在mapper文件中加上一句: <cache /> 
(1).cache所有select的結果 
(2).在同一mapper文件中的insert,update,delete会flush cache 
(3).cache使用least recently used(LRU)算法 
(4).cache没有定时flush的功能 
(5).cache保存1024个对象或list引用 
(6).cache是read/write cache, 从cache拿出对象不是共享的,caller可以任意修改而不用担心其他caller也拿到相同的对象(相同的reference)

9.动态SQL 
以前用jdbc时经常要根据输入条件而组装成不同的sql,这种就是动态sql 
ibatis的动态sql关键词:

if, choose(when,otherwise),trim(where,set),foreach
(1).if
<if test="title != null">
AND title like #{title}
</if>
<![CDATA[
]]>

(2).choose(when,otherwise)只选择其中一种情况

<select ...>
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND title like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>

(3).trim, where, set

<select id="findBlog" paramaterType="Blog" 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 title like ${author.name}
</if>
</where>
</select> <update id="updateAuthorIfNecessary"
parameterType="domain.blog.Author">
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>

(4).foreach

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

10.ibatis的annotation 
ibatis3.0也增加了annotation,当然主要还是用在mapper这个问题上 
个人感觉是鸡肋,暂时不会使用.

Mybayis的项目使用的Mapping文件使用总结参考(一)的更多相关文章

  1. mybayis项目使用的Mapping文件使用总结参考(二)

    针对in字句中的数组使用方法 <select id="getCpProfileNamesByIds" resultType="string"> se ...

  2. 使用mybatis-generator自动生成model、dao、mapping文件

    参考文献:http://www.cnblogs.com/smileberry/p/4145872.html 一.所需库 1.mybatis-generator库 2.连接DB的驱动(此以mysql为例 ...

  3. Android项目实战(二十四):项目包成jar文件,并且将工程中引用的jar一起打入新的jar文件中

    前言: 关于.jar文件: 平时我们Android项目开发中经常会用到第三方的.jar文件. 其实.jar文件就是一个类似.zip文件的压缩包,里面包含了一些源代码,注意的是.jar不包含资源文件(r ...

  4. ANDROID STDUIO 项目里的R文件突然丢失的解决办法N种之一

    刚刚项目里的R文件突然挂了,清理项目,关闭重开Studio,都不能解决.快没折了. 然后只好在项目上右击,看看有没有解决的办法.发现有个 Make Module ,姑且试试吧. 结果,竟然修复了.这是 ...

  5. chrome调试本地项目, 引用本地javascript文件

    chrome调试本地项目, 引用本地javascript文件 本地文件可以访问本地文件 修改快捷方式属性 C:\Users\xxx\AppData\Local\Google\Chrome\Applic ...

  6. 解决eclipse+git中每次clean项目需要重新commit文件

    使用.gitignore文件避免每次clean项目需要重新commit文件(XX.xcodeproj/project.xcworkspace/xcuserdata/XX.xcuserdatad/Use ...

  7. delphi项目中的modelsupport文件夹

    delphi项目中的modelsupport文件夹 今天写着写着突然发现多了一个这个文件夹..苦思不得其解  看着又难受  删了又重建 终于找到了  存此备查;Tools--option--toget ...

  8. iOS之多控制器管理--项目中的常见文件

    项目中的常见文件 内容大纲: 1.LaunchScreen 2.info.plist文件 3.pch文件 1.LaunchScreen xcode5和xcode6区别 1.xcode6没有Framew ...

  9. PTPX中的activity文件以及mapping文件

    在不同的simulation中的capturing switching activity: SAIF:Switching Activity Interface Format,包含toggle coun ...

随机推荐

  1. 跨域跨域跨域,从此say goodbye

    跨域这个问题每个开发者都会遇到,只是时间先后而已,你不搞清楚它他就像狗皮膏药一样粘着你,在你求职生涯中不停的遇到,然后你每次都要做这个功课,终于有一天这个名词已经让我忍无可忍了,下定决心必须搞定它,要 ...

  2. 常用的API

    API (application programming Interface)应用程序编程接口 java 是字典 Scanner类的功能可以实现从键盘输入到程序当中. 引用类型的一般使用步骤 ·1导包 ...

  3. Docker 安装 Tomcat

    查找Docker Hub上的tomcat镜像 docker search tomcat 取官方的镜像 docker pull tomcat 使用tomcat镜像 创建目录tomcat,用于存放后面的相 ...

  4. React—组件生命周期详解

    React—组件生命周期详解 转自 明明的博客  http://blog.csdn.net/slandove/article/details/50748473 (非原创) 版权声明:转载请注明出处,欢 ...

  5. oracle建表字段包含关键字注意事项

    SQL建表时最好不要把表定义成关键字字段 1 若不小心把表定义成关键字了,比如option, desc等等,oracle版本查询会有问题,短期内无法修改字段名称的,暂时用字段名+双引号解决: SELE ...

  6. 使用mybatis出现异常:invalid comparison: java.time.LocalDateTime and java.lang.String

    整了半天终于找到问题所在:在mapper文件中,对该参数进行了和字符串的对比,如下: <if test="startTime != null and startTime != '' a ...

  7. Mac启动Mysql,停止Mysql,重启Mysql

    1.启动mysql sudo /usr/local/mysql/support-files/mysql.server start 2.停止mysql sudo /usr/local/mysql/sup ...

  8. Java网络编程面试总结

    转载. https://blog.csdn.net/qq_39470733/article/details/84635274 1.GET 和 POST 的区别? GET 请求可被缓存 GET 请求保留 ...

  9. session和cookie区别,多台WEB服务器如何共享session,禁用COOKIE后SESSION是否可用,为什么?

    答:session的运行机制: 用户A访问站点Y,如果站点Y指定了session_start();(以下假设session_start()总是存在)那么会产生一个session_id,这个sessio ...

  10. springboot-异步、发送邮件(二)

    @Test //发送复杂邮件 void contextLoads2() throws MessagingException { MimeMessage mimeMessage = mailSender ...