mybatis是一个十分优秀和灵活的持久层框架,前身是ibatis,在此只对mybatis做讲解。
一:在实际的应用中,使用配置文件的方式使我们最常用的,所以这里以配置文件的方式讲解。
mybatis的主配置文件(Configuration.xml)格式如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "> <configuration> <properties/> <!--定义mybatis在运行时的行为方式 --> <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="enhancementEnabled" value="false"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25000"/> </settings> <!--类型别名,即为java类型命名一个短的名字,然后使用该名字。框架已经定义了一些类型—> <typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases><!--类型处理器被用来将获取的值以合适的方式转换成Java类型。框架已经预定义了很多-->
<typeHandlers/><objectFactory/>
<plugins/> <environments default="development"> <environment id="development"> <!—JDBC和MANAGED(它会让容器来管理事务的整个生命周期(比如Spring或JEE应用服务器的上下文))--> <transactionManager type="JDBC"/> <!— UNPOOLED(不使用连接池), POOLED(使用连接池), JNDI(使用JNDI接口获取数据源)。 不同的选项要配置的属性属性也会不一样,但它们都是提供给SqlSessionFactory所使用。 要注意的是,这里的连接池配置是mybatis提供给我们。 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!--sql配置文件--> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>假如定义了一个接口如下:
package org.mybatis.example; public interface BlogMapper{ List getAllMsg() ; BlogModel getMsgById(Integer id) ; } 接着看看mapper配置文件(路径:org/mybatis/example):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "> <mapper namespace="org.mybatis.example.BlogMapper"><resultMap type="com.mybatis.exaple.model.BlogModel" id="blogResulMap">
<id property="id" column="ID" javaType="java.lang.String" jdbcType="VARCHAR"/> <result property="title" column="TITLE" javaType="java.lang.Integer" jdbcType="NUMERIC"/> <result property="content" column="CONTENT" javaType="java.util.Date" jdbcType="TIMESTAMP"/> </resultMap <parameterMap type="com.mybatis.exaple.model.BlogModel" id="blogParametermMap"> <parameter property="id" javaType="java.lang.String" jdbcType="VARCHAR"/> <parameter property="title" javaType="java.lang.Integer" jdbcType="NUMERIC"/> <parameter property="content" javaType="java.util.Date" jdbcType="TIMESTAMP"/> </parameterMap> <select id="getAllMsg" resultType="map"> <![CDATA[ SELECT * FROM BLOG ]]> </select> <select id="getMsgById" parameterType="int" resultMap="blogResulMap"> <![CDATA[ SELECT * FROM BLOG WHERE ID = #{id} ]]> </select> </mapper>二:那如何在应用中启动和使用mybatis呢,操作步骤和解释如下:
1,使用SqlSessionFactoryBuilder来加载配置文件并生成SqlSessionFactory对象。SqlSessionFactory对象在整个应用中应该是单例存在的,并且除非引用被关掉了,否则将一直存在。SqlSessionFactory和数据库实例的关系是一对一。
String resource = "org/mybatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);2,从SqlSessionFactory中获取SqlSession实例。每个线程的每次数据库操作都应该有自己的一个SqlSession,意思说该实例不应该是类的成员属性,而应该是方法的局部变量。
SqlSession session = sqlSessionFactory.openSession();
3,使用session操作数据库(注意,这是mapper文件中已经有id为getAllmsg的sql)
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);List result = mapper.getAllMsg() ;
// do other working } finally { session.close(); }或者
BlogModel model = (BlogModel)session.selectList("org.mybatis.example.BlogMapper.getMsgById",123) ; //namespace+operatorId
注意以下两个符号的使用:
1,#{}(ibatis为:##):MyBatis创建预处理语句属性并以它为背景修改或转义字符串从
而设 置安全的值(比如?)。
常用作查询条件的值,例如:where name=#{value}。 该参数可以指定一个确切的数据类型,例如:#{property,javaType=int,jdbcType=NUMERIC}.
javaType通常可以从参数对象中来确定,除非对象是一个HashMap。 那么javaType应该被确定来保证使用正确类型处理器。 注意:如果null被当作值来传递,对于所有可能为空的列,JDBC Type是需要的.
为了以后自定义类型处理器,你可以指定一个确定的类型处理器类(或别名),比如:
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler} 尽管它看起来繁琐,但是实际上是你很少设置它们其中之一。 对于数值类型,对于决定有多少数字是相关的,有一个数值范围。 #{height,javaType=double,jdbcType=NUMERIC,numericScale=2} 2,${}(ibatis为:$$): MyBatis不会修改或转义字符串,将会直接在SQL语句中插入一个不改变的字符串,常用于拼凑sql的实体部分,
例如:select * from ${tableName}
三:接下来对sql配置映射文件做更深入的说明:
1,select元素
<select
id=”selectPerson” //这条语句的标识。在同一命名空间只能有一个。 parameterType=”int” //传入该语句查询参数的数据类型 parameterMap=”deprecated” //引用外部parameterMap.已经被废弃的方法. resultType=”hashmap” //返回的期望类型的类的完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合本身. resultMap=”personResultMap” //命名引用外部的resultMap.注意:rusultType和resultMap只能使用其一。 flushCache="false" //将其设置为true,无论语句什么时候被调用,都会导致缓存被清空。默认值:false。 useCache="true" //将其设置为true,将会导致本条语句的结果被缓存。默认值:true timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY" >2,insert元素
<insert
id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" //MyBatis会通过getGeneratedKeys或者通过insert语句的selectKey子元素设置它的值。默认:不设置。 /* 这会告诉MyBatis使用JDBC的getGeneratedKeys方法来取出由数据 (比如:像MySQL和SQL Server这样的数据库管理系统的自动递增字段)内部生成的主键。 默认值:false。 */ useGeneratedKeys="" timeout="20000">
例如:
1,如果你的数据库支持自动生成主键的字段
<insert id="insertAuthor" parameterType="domain.blog.Author"
useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>2,如果你的数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。
<insert id="insertAuthor" parameterType="domain.blog.Author">
<selectKey keyProperty="id" resultType="int" order="BEFORE"> select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1 </selectKey> insert into Author ( id, username, password, email,bio, favourite_section) values ( #{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR} ) </insert>对selectKey元素解释:
<selectKey
keyProperty="id" //执行结果应该被设置的目标属性,如上面的Author实例的id属性 /* 结果的类型。MyBatis通常可以算出来,但是写上也没有问题。 MyBatis允许任何简单类型用作主键的类型,包括字符串。 */ resultType="int" /* 这可以被设置为BEFORE或AFTER. BEFORE:首先选择主键,设置keyProperty然后执行插入语句. AFTER:先执行插入语句,然后是selectKey元素, 这和如Oracle数据库相似,可以在插入语句中嵌入序列调用。 */ order="BEFORE" statementType="PREPARED">
3,update元素
<update
id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">
4,delete元素
<delete
id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">
四:结果映射
1,通过resultMap
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap>
<select id=”selectUsers” parameterType="int”
resultMap="userResultMap”> select user_id, user_name, hashed_password from some_table where id = #{id} </select>2,通过resultType
<select id="selectUsers" parameterType="int" resultType="hashmap">
select id, username, hashedPassword from some_table where id = #{id} </select>
<select id="selectUsers" parameterType="int" resultType="hashmap">
select id as id, username as userName, hashedPassword as hashedPassword from some_table where id = #{id} </select>注意:这两种方式得到的map的key都为全大写(ID,USERNAME,HASHEDPASSWORD)即会用列名的全大写作为key值。而下面的方式是指定属性名,在map中就等于指定key值。
<select id="selectUsers" parameterType="int" resultType="hashmap">
select id as "id", username as "userName", hashedPassword as "hashedPassword" from some_table where id = #{id} </select>通过这种方式得到的key为(id,userName,hashedPassword)。
如果返回类型为一个实体对象:
<select id="selectUsers" parameterType="int" resultType="User">
select id, username, hashedPassword from some_table where id = #{id} </select>这些情况下,MyBatis会在幕后自动创建一个ResultMap,基于属性名来映射列到JavaBean的属性上。那如何才能对应上呢?例如:数据库的USERNAME列可以对应上userName属性,而USER_NAME列却不能对应上userName属性。如果匹配不上,我们可以通过下面的两种方式解决。
如果列名没有精确匹配,你可以在列名上使用别名来匹配,例如:
<select id="selectUsers" parameterType="int" resultType="User">
select user_id as id, user_name as username, hashed_password as hashedPassword from some_table where id = #{id} </select>其实这样时候等于是把列名user_name转换为username,然后再中新的列名去和对象的属性相匹配。而下面的这种方式是直接指定user_name列与userName属性相匹配。
<select id="selectUsers" parameterType="int" resultType="User">
select user_id as "id", user_name as "userName", hashed_password as "hashedPassword" from some_table where id = #{id} </select>