MyBatis使用总结

1.MyBatis一般应用步调

1.1获取Configuration实例或编写设备文件

//获取Configuration实例的样例

TransactionFactory transactionFactory = new JdbcTransactionFactory();//定义事务工厂

Environment environment =

new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);

configuration.addMapper(BlogMapper.class);

纸上得来终觉浅,绝知此事要躬行。----陆游《冬夜读书示子聿》

设备文件的编写请看

1.2生成SqlSessionFactory实例(一个数据库对应一个SqlSessionFactory)

//经由过程Configuration实例生成SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);


//经由过程xml设备文件体式格式生成SqlSessionFactory

String resource = "org/mybatis/example/Configuration.xml";

Reader reader = Resources.getResourceAsReader(resource);

sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader);

1.3生成SqlSession实例

//样例

SqlSession session = sqlSessionFactory.openSession();

1.4履行sql各类操纵

//样例

try {

Blog blog = (Blog) session.One("org.mybatis.example.BlogMapper.Blog", 101);

} finally {

session.close();

}

2.MyBatis的设备文件解析

2.1设备文件的根蒂根基布局

• configuration —— 根元素 

o properties —— 定义设备外在化

o settings —— 一些全局性的设备

o typeAliases —— 为一些类定义别号

o typeHandlers —— 定义类型处理惩罚,也就是定义java类型与数据库中的数据类型之间的转换关系

o objectFactory

o plugins —— Mybatis的插件,插件可以批改Mybatis内部的运行规矩

o environments —— 设备Mybatis的景象 

 environment 

 transactionManager —— 事务经管器

 dataSource —— 数据源

o databaseIdProvider

o mappers —— 指定映射文件或映射类

2.2 properties元素——定义设备外在化

<!--样例-->

<properties resource="org/mybatis/example/config.properties">

<property name="username" value="dev_user"/>

<property name="password" value="F2Fa3!33TYyg"/>

</properties>


设备外在化的属性还可以经由过程SqlSessionFactoryBuilder.build()办法供给,如:

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);

设备外在化的优先级是 build办法->resource属性指定的文件->property元素

2.3 settings元素——Mybatis的一些全局设备属性

设置参数 描述 有效值 默认值

cacheEnabled 这个设备使全局的映射器启用或禁用 缓存。 true | false true

lazyLoadingEnabled 全局启用或禁用延迟加载。当禁用时, 所有接洽关系对象都邑即时加载。 true | false true

aggressiveLazyLoading 当启用时, 有延迟加载属性的对象在被 调用时将会完全加载随便率性属性。不然, 每种属性将会按须要加载。 true | false true

multipleResultSetsEnabled 容许或不允很多种成果集从一个零丁 的语句中返回(须要合适的驱动) true | false true

useColumnLabel 应用列标签庖代列名。 不合的驱动在这 便利发挥解析不合。 参考驱动文档或充沛测 试两种办法来决意所应用的驱动。 true | false true

useGeneratedKeys 容许 JDBC 支撑生成的键。 须要合适的 驱动。 若是设置为 true 则这个设置强迫 生成的键被应用, 尽管一些驱动拒绝兼 容但仍然有效(比如 Derby) true | false False

autoMappingBehavior 指定 MyBatis 如何主动映射列到字段/ 属性。PARTIAL 只会主动映射简单, 没有嵌套的成果。FULL 会主动映射任 意错杂的成果(嵌套的或其他景象) 。 NONE, PARTIAL, FULL PARTIAL

defaultutorType 设备默认的履行器。SIMPLE 履行器没 有什么希罕之处。REUSE 履行看重用 预处理惩罚语句。BATCH 履行看重用语句 和批量更新 SIMPLE REUSE BATCH SIMPLE

defaultStatementTimeout 设置超不时候, 它决意驱动守候一个数 据库响应的时候。 Any positive integer Not Set (null)

safeRowBoundsEnabled Allows using RowBounds on nested statements. true | false False

mapUnderscoreToCamelCase Enables automatic mapping classic database column names A_COLUMN to camel case classic Java property names aColumn. true | false False

localCacheScope MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT local session will be used just for statement execution, no data will be shared between two different calls to the same SqlSession. SESSION | STATEMENT SESSION

jdbcTypeForNull Specifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers require specifying the column JDBC type but others work with generic values like NULL, VARCHAR or OTHER. JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER OTHER

lazyLoadTriggerMethods Specifies which Object""s methods trigger a lazy load A method name list separated by commas equals,clone,hashCode,toString

2.4 typeAliases元素——定义类别号,简化xml文件的设备,如:

<typeAliases>

<typeAlias alias="Author" type="domain.blog.Author"/>

<typeAlias alias="Blog" type="domain.blog.Blog"/>

<typeAlias alias="Comment" type="domain.blog.Comment"/>

<typeAlias alias="Post" type="domain.blog.Post"/>

<typeAlias alias="Section" type="domain.blog.Section"/>

<typeAlias alias="Tag" type="domain.blog.Tag"/>

</typeAliases>

Mybatis还内置了一些类型别号:

别号 映射的类型

_byte byte

_long long

_short short

_int int

_integer int

_double double

_float float

_boolean boolean

string String

byte Byte

long Long

short Short

int Integer

integer Integer

double Double

float Float

boolean Boolean

date Date

decimal BigDecimal

bigdecimal BigDecimal

object Object

map Map

hashmap HashMap

list List

arraylist ArrayList

collection Collection

iterator Iterator

2.5 typeHandlers元素

每当MyBatis 设置参数到PreparedStatement 或者从ResultSet 成果集中取得值时,就会应用TypeHandler 来处理惩罚数据库类型与java 类型之间转换。

2.5.1 自定义typeHandlers

1. 实现TypeHandler接口 

View Code

2. 在设备文件中声明自定义的TypeHandler 

View Code

2.5.2 Mybatis内置的TypeHandler

类型处理惩罚器 Java 类型 JDBC 类型

BooleanTypeHandler java.lang.Boolean, boolean 任何兼容的布尔值

ByteTypeHandler java.lang.Byte, byte 任何兼容的数字或字节类型

ShortTypeHandler java.lang.Short, short 任何兼容的数字或短整型

IntegerTypeHandler java.lang.Integer, int 任何兼容的数字和整型

LongTypeHandler java.lang.Long, long 任何兼容的数字或长整型

FloatTypeHandler java.lang.Float, float 任何兼容的数字或单精度浮点型

DoubleTypeHandler java.lang.Double, double 任何兼容的数字或双精度浮点型

BigDecimalTypeHandler java.math.BigDecimal 任何兼容的数字或十进制小数类型

StringTypeHandler java.lang.String CHAR 和 VARCHAR 类型

ClobTypeHandler java.lang.String CLOB 和 LONGVARCHAR 类型

NStringTypeHandler java.lang.String NVARCHAR 和 NCHAR 类型

NClobTypeHandler java.lang.String NCLOB 类型

ByteArrayTypeHandler byte[] 任何兼容的字节俭类型

BlobTypeHandler byte[] BLOB 和 LONGVARBINARY 类型

DateTypeHandler java.util.Date TIMESP 类型

DateOnlyTypeHandler java.util.Date DATE 类型

TimeOnlyTypeHandler java.util.Date TIME 类型

SqlTimestampTypeHandler java.sql.Timestamp TIMESP 类型

SqlDateTypeHandler java.sql.Date DATE 类型

SqlTimeTypeHandler java.sql.Time TIME 类型

ObjectTypeHandler Any 其他或未指定类型

EnumTypeHandler Enumeration Type VARCHAR-任何兼容的字符串类型, 作为代码存储(而不是索引)

EnumOrdinalTypeHandler Enumeration Type Any compatible NUMERIC or DOUBLE, as the position is stored (not the code itself).

2.6 objectFactory元素——用于指定成果集对象的实例是如何创建的。

下面演示了如何自定义ObjectFactory

1.持续DefaultObjectFactory

View Code 

// ExampleObjectFactory.java

public class ExampleObjectFactory extends DefaultObjectFactory {

public Object create(Class type) {

return super.create(type);

}

public Object create(

2.在设备文件中设备自定义的ObjectFactory

View Code 

// MapperConfig.xml

<objectFactory type="org.mybatis.example.ExampleObjectFactory">

<property name="someProperty" value="100"/>

</objectFactory>

2.7 plugins元素

MyBatis 容许您在映射语句履行的某些点阻碍办法调用。默认景象下,MyBatis 容许插件(plugins)阻碍下面的办法:

• utor (, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

• ParameterHandler (getParameterObject, setParameters)

• ResultSetHandler (handleResultSets, handleOutputParameters)

• StatementHandler (prepare, parameterize, batch, , query)

下面是自定义plugin示例:

1. 实现Interceptor接口,并用注解声明要阻碍的办法 

2. // ExamplePlugin.java

3. @Intercepts({@Signature(

4. type= utor.class,

5. method = "",

6. args = {MappedStatement.class,Object.class})})

7. public class ExamplePlugin implements Interceptor {

8. public Object intercept(Invocation invocation) throws Throwable {

9. return invocation.proceed();

10. }

11. public Object plugin(Object target) {

12. return Plugin.wrap(target, this);

13. }

14. public void setProperties(Properties properties) {

15. }

}

16. 在设备文件中声明插件 

View Code

2.8 Environments元素

可以设备多个运行景象,然则每个SqlSessionFactory 实例只能选择一个运行景象。

2.8.1 Environments设备示例:

View Code 

<environments default="development">

<environment id="development">

<transactionManager type="JDBC">

<property name="..." value="..."/>

</transactionManager>

<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>

2.8.2 transactionManager事务经管器

MyBatis 有两种事务经管类型(即type=”[JDBC|MANAGED]”):

• JDBC – 这个设备直接简单应用了 JDBC 的提交和回滚设置。 它依附于从数据源得 到的连接来经管事务局限。

• MANAGED – 这个设备几乎没做什么。它从来不提交或回滚一个连接。而它会让 容器来经管事务的全部生命周期(比如 Spring 或 JEE 应用办事器的高低文) 默认 景象下它会封闭连接。 然而一些容器并不如许, 是以若是你须要从连接中停止 它,将 closeConnection 属性设置为 false。例如: 

• <transactionManager type="MANAGED">

• <property name="closeConnection" value="false"/>

</transactionManager>

自定义事务经管器:

1. 实现TranscactionFactory,它的接口定义如下: 

View Code

2. 实现TransactionFactory,它的接口定义如下: 

3. public interface Transaction {

4. Connection getConnection();

5. void commit() throws SQLException;

6. void rollback() throws SQLException;

7. void close() throws SQLException;

}

2.8.3 dataSource数据源

dataSource 元素应用标准的JDBC 数据源接口来设备JDBC 连接对象源。

MyBatis 内置了三种数据源类型:

UNPOOLED – 这个数据源的实现是每次被恳求时简单打开和封闭连接。它有一点慢, 这是对简单应用法度的一个很好的选择, 因为它不须要及时的可用连接。 不合的数据库对这 个的发挥解析也是不一样的, 所以对某些数据库来说设备数据源并不首要, 这个设备也是闲置的。 UNPOOLED 类型的数据源仅仅用来设备以下 5 种属性:

• driver – 这是 JDBC 驱动的 Java 类的完全限制名(若是你的驱动包含,它也不是 数据源类)。

• url – 这是数据库的 JDBC URL 地址。

• username – 登录数据库的用户名。

• password – 登录数据库的暗码。

• defaultTransactionIsolationLevel – 默认的连接事务隔离级别。

作为可选项,你可以传递数据库驱动的属性。要如许做,属性的前缀是以“driver.”开 头的,例如:

• driver.encoding=UTF8

这 样 就 会 传 递 以 值 “ UTF8 ” 来 传 递 属 性 “ encoding ”, 它 是 通 过 DriverManager.getConnection(url,driverProperties)办法传递给数据库驱动。

POOLED – 这是 JDBC 连接对象的数据源连接池的实现,用来避免创建新的连接实例 时须要的初始连接和认证时候。这是一种当前 Web 应用法度用来快速响应恳求很风行的方 法。

除了上述(UNPOOLED)的属性之外,还有很多属性可以用来设备 POOLED 数据源:

• poolMaximumActiveConnections – 在随便率性时候存在的活动(也就是正在应用)连 接的数量。默认值:10

• poolMaximumIdleConnections – 随便率性时候存在的余暇连接数。

• poolMaximumCheckoutTime – 在被强迫返回之前,池中连接被搜检的时候。默认 值:20000 毫秒(也就是 20 秒)

• poolTimeToWait – 这是给连接池一个打印日记状况机会的低层次设置,还有从头 测验测验获得连接, 这些景象下往往须要很长时候 为了避免连接池没有设备时静默失 败)。默认值:20000 毫秒(也就是 20 秒)

• poolPingQuery – 发送到数据的侦测查询,用来验证连接是否正常工作,并且筹办 接管恳求。默认是“NO PING QUERY SET” ,这会引起很多半据库驱动连接由一 个错误信息而导致失败。

• poolPingEnabled – 这是开启或禁用侦测查询。若是开启,你必须用一个合法的 SQL 语句(最好是很快速的)设置 poolPingQuery 属性。默认值:false。

• poolPingConnectionsNotUsedFor – 这是用来设备 poolPingQuery 多次时候被用一次。 这可以被设置匹配标准的数据库连接超不时候, 来避免不须要的侦测。 默认值: 0(也就是所有连接每一时刻都被侦测-但仅仅当 poolPingEnabled 为 true 时实用)。

JNDI – 这个数据源的实现是为了应用如 Spring 或应用办事器这类的容器, 容器可以集 中或在外部设备数据源,然后放置一个 JNDI 高低文的引用。这个数据源设备只须要两个属 性:

• initial_context – 这 个 属 性 用 来 从 初 始 上 下 文 中 寻 找 环 境 ( 也 就 是 initialContext.lookup(initial——context) 。这是个可选属性,若是被忽视,那么 data_source 属性将会直接以 initialContext 为靠山再次寻找。

• data_source – 这是引用数据源实例地位的高低文的路径。它会以由 initial_context 查询返回的景象为靠山来查找,若是 initial_context 没有返回成果时,直接以初始 高低文为景象来查找。

和其他数据源设备类似, 它也可以经由过程名为 “env.” 的前缀直接向初始高低文发送属性。 比如:

• env.encoding=UTF8

在初始化之后,这就会以值“UTF8”向初始高低文的机关办法传递名为“encoding” 的属性。

 2.9 mappers元素

既然 MyBatis 的行动已经过上述元素设备完了,我们如今就要定义 SQL 映射语句了。 然则, 起首我们须要告诉 MyBatis 到哪里去找到这些语句。 Java 在这方面没有供给一个很好 的办法, 所以最佳的体式格式是告诉 MyBatis 到哪里去找映射文件。 你可以应用相对于类路径的 资料引用,或者字符默示,或 url 引用的完全限制名(包含 file:///URLs) 。例如:

<!-- Using classpath relative resources -->

<mappers>

  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>

  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>

  <mapper resource="org/mybatis/builder/PostMapper.xml"/>

</mappers>

<!-- Using url fully qualified paths -->

<mappers>

  <mapper url="file:///var/mappers/AuthorMapper.xml"/>

  <mapper url="file:///var/mappers/BlogMapper.xml"/>

  <mapper url="file:///var/mappers/PostMapper.xml"/>

</mappers>

<!-- Using mapper interface classes -->

<mappers>

  <mapper class="org.mybatis.builder.AuthorMapper"/>

  <mapper class="org.mybatis.builder.BlogMapper"/>

  <mapper class="org.mybatis.builder.PostMapper"/>

</mappers>

<!-- Register all interfaces in a package as mappers -->

<mappers>

  <package name="org.mybatis.builder"/>

</mappers>

3. MyBatis 3中实现一对多的插入和查询

MyBatis3中实现一对多的查询比较简单,可以自动完成。但插入操作要复杂一些,需要相关的DAO配合完成,这点不如Hibernate。


场景描述:

类:Mail和Attachment类

关系描述:一封邮件(Mail)可以有0个或多个附件(Attachment),附件(Attachment)仅对应一封邮件。

表格:mail表(主键:id_mail)和attachment表(外键:id_mail)。


POJO: Mail.java

[java] view plaincopyprint?

public class Mail implements Serializable {  

    private static final long serialVersionUID = 7427977743354005783L;  

    private Integer id;  

    private String sender;  

    private String subject;  

    private String content;  

    private String fromAddress;  

...  

getters and setters...  

}  

public class Mail implements Serializable { private static final long serialVersionUID = 7427977743354005783L; private Integer id; private String sender; private String subject; private String content; private String fromAddress; ... getters and setters... }

Attachment.java

[java] view plaincopyprint?

public class Attachment implements Serializable {  

    private static final long serialVersionUID = -1863183546552222728L;  

    private String id;  

    private String mailId;  

    private String name;  

    private String relativePath;  

...  

getters and setters...  

}  

public class Attachment implements Serializable { private static final long serialVersionUID = -1863183546552222728L; private String id; private String mailId; private String name; private String relativePath; ... getters and setters... } SqlMapConfig:

[html] view plaincopyprint?

<?xml version="1.0" encoding="UTF-8"?>  

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  

<configuration>  

    <properties resource="test/properties/mysql.properties"></properties>  

      

    <typeAliases>  

        <typeAlias type="test.model.Mail" alias="Mail"/>  

        <typeAlias type="test.model.Attachment" alias="Attachment"/>        

    </typeAliases>  

      

      

    <environments default="development">  

        <environment id="development">  

            <transactionManager type="JDBC" />  

            <dataSource type="UNPOOLED">  

                <property name="driver" value="${db_driver}" />  

                <property name="url" value="${db_url}" />  

                <property name="username" value="${db_user}" />  

                <property name="password" value="${db_password}"/>  

            </dataSource>  

        </environment>  

    </environments>    

          

    <mappers>  

    <mapper resource="test/data/MailMapper.xml"/>  

    <mapper resource="test/data/AttachmentMapper.xml"/>  

    </mappers>      

</configuration>  

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="test/properties/mysql.properties"></properties> <typeAliases> <typeAlias type="test.model.Mail" alias="Mail"/> <typeAlias type="test.model.Attachment" alias="Attachment"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="UNPOOLED"> <property name="driver" value="${db_driver}" /> <property name="url" value="${db_url}" /> <property name="username" value="${db_user}" /> <property name="password" value="${db_password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="test/data/MailMapper.xml"/> <mapper resource="test/data/AttachmentMapper.xml"/> </mappers> </configuration> Mappers MailMapper.xml

[html] view plaincopyprint?

<?xml version="1.0" encoding="UTF-8"?>  

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  

<mapper namespace="test.data.MailMapper">  

    <cache />  

  

    <resultMap type="Mail" id="result_base">  

        <id property="id" column="id_mail" />  

        <result property="sender" column="sender"/>  

        <result property="fromAddress" column="from_address" />  

        <result property="subject" column="subject"/>  

        <result property="content" column="content"/>  

        <result property="sendTime" column="send_time" />  

            ....  

    </resultMap>  

    <!--这里是关键,一对多映射的“魔法”几乎都在<collection>的配置里。select=...中"test.data.AttachmentMapper"对应于AttachmentMapper中  

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="test.data.MailMapper"> <cache /> <resultMap type="Mail" id="result_base"> <id property="id" column="id_mail" /> <result property="sender" column="sender"/> <result property="fromAddress" column="from_address" /> <result property="subject" column="subject"/> <result property="content" column="content"/> <result property="sendTime" column="send_time" /> .... </resultMap> <!--这里是关键,一对多映射的“魔法”几乎都在<collection>的配置里。select=...中"test.data.AttachmentMapper"对应于AttachmentMapper中

[html] view plaincopyprint?

            的namespace-->  

    <resultMap type="Mail" id="result" extends="result_base">  

        <collection property="attachments" javaType="ArrayList" column="id_mail" ofType="Attachment"   

        select="test.data.AttachmentMapper.selectByMailId"/>  

    </resultMap>  

      

    <insert id="insert" parameterType="Mail" useGeneratedKeys="true" keyProperty="id_note">  

        insert into note(sender, from_address, subject, content, send_time)  

        values(#{sender}, #{fromAddress}, #{subject}, #{content}, #{sendTime})  

        <selectKey keyProperty="id_mail" resultType="int">   

                      select LAST_INSERT_ID()   

                </selectKey>   

    </insert>  

      

    <select id="selectById" parameterType="int" resultMap="result" >  

        select * from mail where id_mail = #{id}  

    </select>  

      

    <select id="selectAllMails" resultMap="result">  

        select * from note Note  

    </select>  

    <!--这里可以获得刚插入表格的id,为后面attachment的插入提供了mailId字段-->  

    <select id="selectLastId" resultType="int">  

         select LAST_INSERT_ID()   

    </select>  

</mapper>  

的namespace--> <resultMap type="Mail" id="result" extends="result_base"> <collection property="attachments" javaType="ArrayList" column="id_mail" ofType="Attachment" select="test.data.AttachmentMapper.selectByMailId"/> </resultMap> <insert id="insert" parameterType="Mail" useGeneratedKeys="true" keyProperty="id_note"> insert into note(sender, from_address, subject, content, send_time) values(#{sender}, #{fromAddress}, #{subject}, #{content}, #{sendTime}) <selectKey keyProperty="id_mail" resultType="int"> select LAST_INSERT_ID() </selectKey> </insert> <select id="selectById" parameterType="int" resultMap="result" > select * from mail where id_mail = #{id} </select> <select id="selectAllMails" resultMap="result"> select * from note Note </select> <!--这里可以获得刚插入表格的id,为后面attachment的插入提供了mailId字段--> <select id="selectLastId" resultType="int"> select LAST_INSERT_ID() </select> </mapper> AttachmentMapper.xml

[html] view plaincopyprint?

<?xml version="1.0" encoding="UTF-8"?>  

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  

<mapper namespace="test.data.AttachmentMapper">  

    <cache />  

      

    <resultMap type="Attachment" id="result">  

        <result property="id" column="id_accessory" />  

        <result property="name" column="name" />  

        <result property="relativePath" column="relative_path" />  

        <result property="mailId" column="id_mail" />  

    </resultMap>  

      

    <insert id="insert" parameterType="Attachment">  

        insert into attachments(id_mail, name, relative_path) values(#{mailId}, #{name}, #{relativePath})  

    </insert>  

    <!--MailMapper中的ResultMap调用这个方法来进行关联-->  

    <select id="selectByMailId" parameterType="int" resultMap="result">  

        select  id, id_mail, name, relative_path  

         from attachments where id_note = #{id}  

    </select>  

</mapper>  

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="test.data.AttachmentMapper"> <cache /> <resultMap type="Attachment" id="result"> <result property="id" column="id_accessory" /> <result property="name" column="name" /> <result property="relativePath" column="relative_path" /> <result property="mailId" column="id_mail" /> </resultMap> <insert id="insert" parameterType="Attachment"> insert into attachments(id_mail, name, relative_path) values(#{mailId}, #{name}, #{relativePath}) </insert> <!--MailMapper中的ResultMap调用这个方法来进行关联--> <select id="selectByMailId" parameterType="int" resultMap="result"> select id, id_mail, name, relative_path from attachments where id_note = #{id} </select> </mapper>

DAO

AttachmentDAO

[java] view plaincopyprint?

public class AttachmentDAO {  

    private SqlSessionFactory sqlSessionFactory;  

      

    public AttachmentDAO(){  

        this.sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory();  

    }  

      

    public void insert(Attachment attachment){  

             SqlSession session = sqlSessionFactory.openSession();  

             AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class);   

             try {  

                attachmentMapper.insert(attachment);  

                session.commit();  

             } finally {  

                session.close();  

             }  

    }  

}  

public class AttachmentDAO { private SqlSessionFactory sqlSessionFactory; public AttachmentDAO(){ this.sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory(); } public void insert(Attachment attachment){ SqlSession session = sqlSessionFactory.openSession(); AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class); try { attachmentMapper.insert(attachment); session.commit(); } finally { session.close(); } } }

MailDAO

[java] view plaincopyprint?

public class MailDAO {  

    private SqlSessionFactory sqlSessionFactory;  

public class MailDAO { private SqlSessionFactory sqlSessionFactory;

[java] view plaincopyprint?

public MailDAO(){  

    sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory();  

}   

  

public void insertMailOnly(Mail mail){  

    SqlSession session = sqlSessionFactory.openSession();  

    MailMapper mailMapper = session.getMapper(MailMapper.class);  

    try {  

        mailMapper.insert(mail);         

        session.commit();  

    } finally {  

        session.close();  

    }  

}   

//inset    

public void insertMail(Mail mail){  

    SqlSession session = sqlSessionFactory.openSession();  

    MailMapper mailMapper = session.getMapper(MailMapper.class);  

    AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class);  

      

    try{  

    mailMapper.insert(mail);  

    //这里必须commit,再执行Attachment的插入操作。否则会导致null pointer异常   

    session.commit();  

    //获得最近插入到note表的id   

    int mailId = mailMapper.selectLastId();  

    for(Attachment attach : mail.getAttachments()){  

        attach.setMailId(String.valueOf(mailId));  

        attachmentMapper.insert(attach);  

    }  

    session.commit();  

    }finally{  

        session.close();  

    }  

}  

  

public ArrayList<Mail> selectAllMails(){        

    ArrayList<Mail> mailList = null;  

    SqlSession session = sqlSessionFactory.openSession();  

    MailMapper mailMapper = session.getMapper(MailMapper.class);  

    try {             

        mailList = mailMapper.selectAllMails();  

        session.commit();  

    } finally {  

        session.close();  

    }  

urn mailList;  

}   

  

public Mail selectMailById(int i){  

    Mail mail = null;  

    SqlSession session = sqlSessionFactory.openSession();  

    MailMapper mailMapper = session.getMapper(MailMapper.class);  

    try {             

        mail = mailMapper.selectById(i);  

        session.commit();  

    } finally {  

        session.close();  

    }  

urn mail;  

}  

  

public int selectLastId(){  

    int id = -1;  

    SqlSession session = sqlSessionFactory.openSession();  

    MailMapper mailMapper = session.getMapper(MailMapper.class);  

    try {             

        id = mailMapper.selectLastId();  

        session.commit();  

    } finally {  

        session.close();  

    }  

urn id;  

}  

4. ibatis如何支持clob 和blob

这几天仔细看了一下ibatis的文档,发现2.2后,ibatis的改变还是挺大的。对于自定义类型支持的也不错,这样对于blob和clob数据的处理也就简单多了。

    不过在spring 中已经提供了很好的实现,所以这又省去了很多的功夫,接下来看看ibatis是如何支持clob和blob的。

    ibatis提供了TypeHandler接口,用于处理数据类型,基本的实现类为BaseTypeHandler

    在spring 中,提供了AbstractLobTypeHandler作为基础类,并且提供了相应的模版方法,所有的工作由LobHandler处理。

    BlobByteArrayTypeHandler 主要用于处理blob类型数据,使用byte[]来映射相应的blob

    ClobStringTypeHandler 用于处理clob类型数据,使用字符串来映射Clob

    有一点需要注意的是,AbstractLobTypeHandler中实现了事务支持,需要用来释放相应的资源,所以一定需要在事务环境中进行。


下面是一个简单的例子:


public class Food {

    private String content;


    private String id;


    private byte[] image;


    private String name;    

        ...

}


xml如下:说明一下,在resultMap中可以通过typeHandler来指定具体的handler.在inline变量中,可以通过handler来定义相应的typeHandler


<sqlMap namespace="Food">

    

    <typeAlias alias="Food" type="org.esoft.hdb.bo.Food"/>

    <resultMap id="foodResult" class="Food">

        <result property="id" column="C_ID"/>

        <result property="name" column="C_NAME"/>

        <result property="content" column="C_content"

            typeHandler="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>

        <result property="image" column="C_image"

            typeHandler="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler"/>

    </resultMap>

    <sql id="foodFragment">select C_ID,C_NAME,C_CONTENT,C_IMAGE from T_FOOD</sql>

        <select id="getAll" resultMap="foodResult">

        <include refid="foodFragment"/>

    </select>

    <select id="selectById" parameterClass="string" resultMap="foodResult">

        <include refid="foodFragment"/> where C_ID=#id#</select>

    

    <insert id="insert" parameterClass="Food"> insert into T_FOOD ( C_ID,

        C_NAME,C_CONTENT, C_IMAGE) values ( #id#,

        #name#,#content,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#,

        #image,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#)

        </insert>

    

    <update id="update" parameterClass="Food"> update T_FOOD set C_NAME = #name#,

        C_CONTENT =

        #content,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#,

        C_IMAGE =

        #image,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#

        where C_ID = #id# </update>

    

    <delete id="deleteById" parameterClass="string"> delete from T_FOOD where C_ID = #id#

        </delete>

    

</sqlMap>



public interface FoodService {


    

    void save(Food food);

    Food get(String id);

    /**

     * @param food

     */

    void update(Food food);

}


public class FoodServiceImpl implements FoodService {

     private FoodDAO foodDAO;


    private DaoCreator creator;


    public void setCreator(DaoCreator creator) {

        this.creator = creator;

    }


    protected FoodDAO getFoodDAO() {

        if (foodDAO == null) {

            foodDAO = (FoodDAO) creator.createDao(FoodDAO.class, Food.class);

        }

        return foodDAO;

    }


    public Food get(String id) {

        return getFoodDAO().get(id);

    }

    public void save(Food food) {

        getFoodDAO().save(food);

    }

    public void update(Food food) {

        getFoodDAO().update(food);

    }


}


spring xml 配置:

。。。

          <bean id="lobHandler"

        class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>

    

    <bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource"/>

    </bean>

    

    <bean id="sqlMapClient"

        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

        <property name="dataSource" ref="dataSource"/>

        <property name="configLocation">

            <value>SqlMapConfig.xml</value>

        </property>

        <property name="lobHandler" ref="lobHandler"/>

    </bean>

    

    <bean id="daoCreate" class="org.esoft.hdb.ibatis.IbatisDaoCreator">

        <property name="sqlMapClient" ref="sqlMapClient"/>

    </bean>

    

    <bean id="foodService" class="org.esoft.hdb.service.FoodServiceImpl">

        <property name="creator" ref="daoCreate"/>

    </bean>

    

    

    <aop:config>

        <aop:pointcut id="foodServiceMethods"

            expression="execution(* org.esoft.hdb.service.FoodService.*(..))"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="foodServiceMethods"/>

    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="*" propagation="REQUIRED"/>

        </tx:attributes>

    </tx:advice>


简单的测试:

save :

        Food food = new Food();

        food.setPk("1");

        food.setName("food1");

        BufferedInputStream in = new BufferedInputStream(getClass()

                .getResourceAsStream("/1.gif"));

        byte[] b = FileCopyUtils.copyToByteArray(in);

        food.setImage(b);

                in = new BufferedInputStream(getClass().getResourceAsStream(

                "/hibernate.cfg.xml"));

        b = FileCopyUtils.copyToByteArray(in);

        food.setContent(new String(b));

        foodService.save(food);

update:

              Food food = foodService.get("1");

        BufferedInputStream in = new BufferedInputStream(getClass()

                .getResourceAsStream("/jdbc.properties"));

        byte[] b = FileCopyUtils.copyToByteArray(in);

        food.setContent(new String(b));

        foodService.update(food);

        food = foodService.get("1");

        assertNotNull(food.getImage());

5. TypeHandler的实例

TypeHandler是MyBatis config文件中可选的配置选项,其可以对实体属性类型和数据库列类型的转换过程进行干涉,在过程中添加某些可能需要的操作。 

1、自定义的typeHandler类需要实现typeHandler接口并且实现接口方法; 

2、配置文件添加<typeHandler>; 

3、在映射文件中的参数和结果添加类型说明,javaType和jdbcType。 

简单实例如下: 


1.类型控制类 


Java代码   

1. package com.chl.mybatis.typehandler;    

2.    

3. import java.sql.CallableStatement;    

4. import java.sql.PreparedStatement;    

5. import java.sql.ResultSet;    

6. import java.sql.SQLException;    

7.    

8. import org.apache.ibatis.type.JdbcType;    

9. import org.apache.ibatis.type.TypeHandler;    

10.    

11.    

12. /**  

13. * @author chl  

14. * 类型转换器  

15. * 实现TypeHandler接口  

16. * 需要强调的是:为了让类型控制器起作用,必须在mapper.xml中对参数和结果的类型进行显示表明。  

17. */    

18. public class StringVarcharTypeHandler implements TypeHandler{    

19.    

20.    @Override    

21.    public Object getResult(ResultSet rs, String columnName) throws SQLException {    

22.        // TODO Auto-generated method stub    

23.        System.out.println("getResult(rs,columnName)");    

24.        return rs.getString(columnName);    

25.    }    

26.    

27.    @Override    

28.    public Object getResult(CallableStatement arg0, int arg1)    

29.            throws SQLException {    

30.        // TODO Auto-generated method stub    

31.        return null;    

32.    }    

33.    

34.    @Override    

35.    public void setParameter(PreparedStatement ps, int paraIndex, Object object,    

36.            JdbcType jt) throws SQLException {    

37.        // TODO Auto-generated method stub    

38.        System.out.println("setParameter()");    

39.        ps.setString(paraIndex, (String)object);    

40.    }    

41.    

42. }   


2.配置文件中添加类型控制器配置 


Xml代码   

1. <!-- 类型处理器 -->    

2. <typeHandlers>    

3.    <typeHandler javaType="String" jdbcType="VARCHAR"     

4.        handler="com.chl.mybatis.typehandler.StringVarcharTypeHandler"/>    

5. </typeHandlers>   


3.映射文件中添加类型说明 


Xml代码   

1. <select id="selectUsers" resultMap="userMap">    

2.    select username, sex from t_user;    

3. </select>    

4.    

5. <insert id="insertUser" parameterType="User">    

6.    insert into t_user (username, sex)     

7.    values     

8.    (#{userName, javaType=String, jdbcType=VARCHAR},    

9.    #{sex, javaType=String, jdbcType=VARCHAR});    

10. </insert>    

11.    <!-- 实现结果中列于对象属性的对应关系,利用javaType和jdbcType表示类型关系,这样有助于TypeHandler的匹配使用 -->    

12. <resultMap id="userMap" type="User">    

13.    <result property="userName" column="username" javaType="String" jdbcType="VARCHAR"></result>    

14.    <result property="sex" column="sex" javaType="String" jdbcType="VARCHAR"></result>    

15. </resultMap>    

6. Mybatis哲学

MyBatis上层接口使用简单工厂模式,核心接口为org.apache.ibatis.session.SqlSession。其中定义了与数据相关的所有操作,以及和MyBatis本身相关的几个方法,比如getConfiguration和getMapper。下图列出了部分常用方法:


     

     从上面的类图中可以看出,SqlSession已经覆盖了DAO模式中的所有方法。因为是ORM框架,所以都是包装方法。但如果在特殊情况下,一定要用JDBC原始java.sql.Connection接口的话,SqlSession中也提供了getConnection这个方法来获取。可以想象,这只有在很特别的情况下才会用到,因为此后,你对java.sql.Connection所做的任何操作都与MyBatis无关了,它提供的所有功能也因此不再有效,如事务等,都需要自己手动来管理了。


     上面提到,MyBatis的上层核心接口是SqlSession,因此,上层的其它接口和类,均围绕它展开。下面从一个官方应用指南中的经典API例子开始,引出这几个重要的类。

点击(此处)折叠或打开

1. String evironment= "development";

2. InputStream is = getClass().getResourceAsStream("/SqlMapperConfig.xml");

3. SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();

4. SqlSessionFactory factory = factoryBulider.bulid(is,evironment);

5. SqlSession session = factory.openSession();

6. String selectId = "test.foo";

7. Object bean = session.selectOne(selectdId);

8. session.close;

   这是一个简单的查询,涉及到下面这几个类,它们是使用的MyBatis的入口:


• org.apache.ibatis.session.SqlSessionFactoryBuilder : SQL会话工厂的构建类

• org.apache.ibatis.session.SqlSessionFactroy : 打开一个SQL会话的工厂类

• org.apache.ibatis.session.SqlSession : SQL会话本身

• org.apache.ibatis.session.Configuration : 整个MyBatis的配置

   似乎有点太简单了 ,其实不然,这只是入口。关键的地方是SqlSessionFactory这个接口的实例是如何被创建出来的呢?显然答案就在SqlSessionFactoryBuilder这个默认实用类中。另外,org.apache.ibaits.session.Configuration这个类是怎么冒出来的呢?答案也在SqlSessionFactoryBuilder的实现代码里,那还等什么,源码List出来吧:

点击(此处)折叠或打开

1. public class SqlSessionFactoryBuilder {

2.  public SqlSessionFactory build(Readerreader) {

3.    return build(reader,null, null);

4.  }

5.  

6.  public SqlSessionFactory build(Readerreader, String environment){

7.    return build(reader,environment,null);

8.  }

9.  

10.  public SqlSessionFactory build(Readerreader, Properties properties){

11.    return build(reader,null, properties);

12.  }

13.  

14.  public SqlSessionFactory build(Readerreader, String environment,Properties properties){

15.    try {

16.      XMLConfigBuilder parser = new XMLConfigBuilder(reader,environment,properties);

17.      return build(parser.parse());

18.    } catch(Exception e){

19.      throw ExceptionFactory.wrapException("Error building SqlSession.", e);

20.    } finally{

21.      ErrorContext.instance().reset();

22.      try {reader.close();catch(IOException e){//Intentionally ignore. Prefer previous error.}

23.    }

24.  }

25.

26.  public SqlSessionFactory build(InputStreaminputStream){

27.    return build(inputStream,null, null);

28.  }

29.

30.  public SqlSessionFactory build(InputStreaminputStream,String environment){

31.    return build(inputStream,environment,null);

32.  }

33.

34.  public SqlSessionFactory build(InputStreaminputStream,Properties properties){

35.    return build(inputStream,null, properties);

36.  }

37.

38.  public SqlSessionFactory build(InputStreaminputStream,String environment,Properties props){

39.    try {

40.      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream,environment,props);

41.      return build(parser.parse());

42.    } catch(Exception e){

43.      throw ExceptionFactory.wrapException("Error building SqlSession.", e);

44.    } finally{

45.      ErrorContext.instance().reset();

46.      try{inputStream.close();}catch(IOException e){//Intentionally ignore.Prefer previous error.}

47.    }

48.  }

49.    

50.  public SqlSessionFactory build(Configurationconfig) {

51.    return new DefaultSqlSessionFactory(config);

52.  }

53. }

   从它的类签名和构造方法签名就可以看出,这个类是即用即扔的,正好与MyBatis源码赏析一中提到的生命周期相吻合。这个类只有一个方法,就是build。build方法被重载(overide)了多次,可分为三组:


1. 通过指定org.apache.ibais.session.Configuration来构建DefaultSqlSessionFactory

2. 从一个Reader中加载Configuration,并构建SqlSessionFactory

3. 从一个Stream中加载Configuration,并构建SqlSessionFactory

  2和3又被重载了多次,但最终,这两类build方法的任务都是从不同的源加载配置,而SqlSessionFactory具体的构建过程,则委托给1类这个build方法。由此可见,SqlSessionFactoryBuilder这个类,其实也没做什么,只是从不同的源加载配置,为编程提供入口。而具体的加载过程都委托给了其它类。


  从SqlSessionFactoryBuilder中构建出来的工厂实现类,都是DefaultSqlSessionFactory,这是MyBatis默认的SqlSessionFactory接口的实现类,也是唯一一个真实的实现类,在本文的版本中(3.0.6),还有另外一个实现类:SqlSessionManager,但它并不是一个功能上的实现类,而是对SqlSession在实际应用开发过程中的实用工具类。因此,现在的重点落在了DefaultSqlSessionFactory类。SqlSessionFactory的功能是负责打开一个连接会话,该接口只定义了两个方法如下:

点击(此处)折叠或打开

1. public interface SqlSessionFactory {

2.  SqlSession openSession();

3.

4.  SqlSession openSession(boolean autoCommit);

5.  SqlSession openSession(Connectionconnection);

6.  SqlSession openSession(TransactionIsolationLevellevel);

7.

8.  SqlSession openSession(ExecutorType execType);

9.  SqlSession openSession(ExecutorType execType,boolean autoCommit);

10.  SqlSession openSession(ExecutorType execType, TransactionIsolationLevellevel);

11.  SqlSession openSession(ExecutorType execType,Connection connection);

12.

13.  Configuration getConfiguration();

14. }

  可以看出,主要就是openSession方法,通过重载多次,来得到不同的会话特性。再看看DefaultSqlSessionFactory是如何实现openSession这个方法的。这儿就不贴出源码了,所有的openSession方法最终通过转调两个方法来实现的,分别是openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,boolean autoCommit)和openSessionFromConnection(ExecutorType execType, Connection connection),这样做显然是因为SqlSessionFactory接口的openSession方法签名就被这样分成了两类,FromDataSource这一类的,显然是通过DataSource来获取java.sql.Connection的,FromConnection则是直接指定Connection的。这里我们可以看出,这样做的目的在最高层提供了灵活性,也是手工编程的入口。虽然我们实际开发过程中,都是通过配置xml的方式来使用MyBatis的。但了解到这些后,为我们自己扩展MyBatis提供了入口。

  

  现在还剩下一个问题,前面提到的几个高层接口都找到了相应的实现类,那SqlSession呢?它的实现类是什么?当然你用Eclipse或是NetBeans这些高级IDE可以一下子找到,不过,我们这儿另辟溪径。我们知道,一个SqlSession的实例是这样得到的:SqlSessionFactoryBuilder.build(...).openSession(...);而build方法返回的是DefaultSqlSessionFactory实现类,查看一下这它的openSession方法不就知道了么。是的,如前段所述,最终我们可以在openSessionFromDataSource和openSessionFromConnection这两个方法中找到,得到的SqlSession实现类是org.apache.ibatis.session.defaults.DefaultSqlSession。再进入到该类中,在这儿,我们就快要接近真相(我们想知道,SqlSession的CRUD操作是如何实现的)了。其实,具体CRUD操作,都委托给了org.apache.ibaits.executors.Executor接口了。DefaultSqlSession只是为Executor提供执行参数和环境,是一个管理者,下面是它开头的部分源码:

点击(此处)折叠或打开

1. public class DefaultSqlSession implements SqlSession{

2.

3.  private Configurationconfiguration;

4.  private Executorexecutor;

5.

6.  private boolean autoCommit;

7.  private booleandirty;

8.

9.  public DefaultSqlSession(Configurationconfiguration,Executor executor,boolean autoCommit){

10.    this.configuration= configuration;

11.    this.executor= executor;

12.    this.autoCommit= autoCommit;

13.    this.dirty= false;

14.  }

15.  ....

16. }

  可以看出,它主要管理维护两个类实例,分别是Executor和Configuration。顾名思义,前者负责执行,后者负责提供数据,而SqlSession本身则身负将二者关联起来,加以管理。


  通过前面的分析,我们大致可以得到MyBatis一个粗略的上层架构类图:

 

  作为一名一线应用开发人员,“配置”一词,可能已经听得耳朵都长茧了。但是,一个程序或者说是一个库,具有可配置性,是非常必要的,否则就得以纯编程的方式使用它们。试想一下,如果你在使用数据库产品时,你还需要通过编程来使用,那将是多么地糟糕!


     配置不仅仅是使用的人要用,这个库或者框架的开发者自己也需要用,否则,如何组织内部的各个构件,将会是一件硬编码的事情。总之,配置,就是要组织出一个完整的逻辑或形式系统,以达到使用者的目的。在框架内部来说,通过配置,还在看清楚整个架构。


     通过MyBatis的配置,可以看出整个框架的顶级特性。为什么这么说呢,把这些代码列出来就一目了然了。

点击(此处)折叠或打开

1. public class Configuration {

2.

3.  protected Environmentenvironment;

4.

5.  protected boolean safeRowBoundsEnabled= true;

6.  protected boolean mapUnderscoreToCamelCase= false;

7.  protected boolean lazyLoadingEnabled= false;

8.  protected boolean aggressiveLazyLoading= true;

9.  protected boolean multipleResultSetsEnabled= true;

10.  protected boolean useGeneratedKeys= false;

11.  protected boolean useColumnLabel= true;

12.  protected boolean cacheEnabled= true;

13.  protected Integer defaultStatementTimeout;

14.  protected ExecutorType defaultExecutorType= ExecutorType.SIMPLE;

15.  protected AutoMappingBehavior autoMappingBehavior= AutoMappingBehavior.PARTIAL;

16.

17.  protected Properties variables= new Properties();

18.  protected ObjectFactoryobjectFactory =new DefaultObjectFactory();

19.  protected ObjectWrapperFactory objectWrapperFactory= new DefaultObjectWrapperFactory();

20.  protected MapperRegistry mapperRegistry = new MapperRegistry(this);

21.

22.  protected final InterceptorChain interceptorChain= new InterceptorChain();

23.  protected final TypeHandlerRegistry typeHandlerRegistry= new TypeHandlerRegistry();

24.  protected final TypeAliasRegistry typeAliasRegistry= new TypeAliasRegistry();

25.  protected finalMap<String, MappedStatement> mappedStatements= new StrictMap<String,MappedStatement>("Mapped Statements collection");

26.  protected finalMap<String, Cache> caches= new StrictMap<String, Cache>("Caches collection");

27.  protected finalMap<String, ResultMap> resultMaps= new StrictMap<String, ResultMap>("Result Maps collection");

28.  protected finalMap<String, ParameterMap> parameterMaps= new StrictMap<String,ParameterMap>("Parameter Maps collection");

29.  protected finalMap<String,KeyGenerator> keyGenerators= new StrictMap<String,KeyGenerator>("Key Generators collection");

30.

31.  protected finalSet<String> loadedResources= new HashSet<String>();

32.  protected finalMap<String, XNode> sqlFragments= new StrictMap<String, XNode>("XML fragments parsed from previous mappers");

33.

34.  protected finalCollection<XMLStatementBuilder> incompleteStatements= newLinkedList<XMLStatementBuilder>();

35.  protected finalCollection<CacheRefResolver> incompleteCacheRefs= newLinkedList<CacheRefResolver>();

36.  protected finalCollection<ResultMapResolver> incompleteResultMaps= newLinkedList<ResultMapResolver>();

37.  /**

38.   * A map holds cache-ref relationship. The key is the namespace that

39.   * references a cache bound to another namespace and the value is the

40.   * namespace which the actual cache is bound to.

41.   */

42.  protected finalMap<String,String> cacheRefMap= new HashMap<String,String>();

43.

44.  public Configuration(Environmentenvironment){

45.    this();

46.    this.environment= environment;

47.  }

48.

49.  public Configuration(){

50.    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class.getName());

51.    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class.getName());

52.    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class.getName());

53.    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class.getName());

54.    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class.getName());

55.

56.    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class.getName());

57.    typeAliasRegistry.registerAlias("FIFO", FifoCache.class.getName());

58.    typeAliasRegistry.registerAlias("LRU", LruCache.class.getName());

59.    typeAliasRegistry.registerAlias("SOFT", SoftCache.class.getName());

60.    typeAliasRegistry.registerAlias("WEAK", WeakCache.class.getName());

61.  }

62.

63. ......

64. }

    通过这些字段的名字,我们就可以知道,MyBatis所支持的顶级特性了。之所以叫顶级特性,是因为这些字段出现在顶级配置中,其它一些边缘特性则隐藏在各个字段的实现里。当然,有些不能叫做特性,而应该叫基本术语或基础概念。对应上面的字段,下面列出这些特性或术语:


     数据环境(包括数据源和事务)

     是否启用严格的行绑定

     是否启用下划线与驼峰式命名规则的映射(如first_name => firstName)

     是否启用懒加载模式

     是否启用贪婪地懒加载模式(即尽可能多地使用懒加载)

     是否启用多结果集映射

     是否启用主键生成功能

     是否启用采用列标签功能(如果不启用,则使用下标索引)

     是否启用缓存功能

     默认的JDBC语句超时设置

     默认的执行器类型(共有SIMPLE,REUSE和BATCH三种)

     初始化SqlMapping自动映射行为(共有NONE,PARTIAL和FULL三种)

     

     其它文本属性(作为扩展或使用者自己用,存放在Promerties中)

     初始化生成对象(实例)的工厂

     初始化对象的包装工厂(用于代理,完成一些重要的特性,比如事务)

     初始化SqlMapping的映射器

     

     初始化拦截器链

     初始化类型处理注册器(默认的注册器就已经预注册了常见的类型)

     初始化类型别名注册器

     初始化JDBC语句容器(就是一个Map,下同)

     初始化缓存

     初始化结果集容器

     初始化参数容器

     初始化主键生成器容器

     

     初始化化已经加的载资源容器

     初始化SQL语句片断容器(SQL语句片断,是可重用的,相信大家在Mapping文件中经常用到)

     

     初始化不完整的JDBC语句容器(显然这个语句还没有执行插值操作)

     初始化不完整的缓存引用容器

     初始化不完整的结果集映射容器

     

     初始化缓存引用容器

     ----------------------------------------------------


     Configuration默认有两个构造器,一个是无参的,另一个则需要指定数据环境。但指定数据环境的这个构造器首先调用了无参的构造器。通过上面的源码,我们可以看到,无参构造器主要是注册了一些重要的类型别名,这些别名在XML配置中会用到。整个Configuration的所有字段都已经初始化了,除了environmnet。因此,它还提供一个传递数据环境的构造器。

     

      Configuration是所有组件的有机组合器,同时也是运行时数据收集器,它会在DefaultSqlSession中用到,并再次传递给Executor接口,它们都依赖它。可以说它是拼接整个MyBatis应用的核心人物,就像Spring在应用程序开发中的地位。


summary:

MyBatis3中实现一对多的查询比较简单,可以自动完成。但插入操作要复杂一些,需要相关的DAO配合完成,这点不如Hibernate。


场景描述:

类:Mail和Attachment类

关系描述:一封邮件(Mail)可以有0个或多个附件(Attachment),附件(Attachment)仅对应一封邮件。

表格:mail表(主键:id_mail)和attachment表(外键:id_mail)。


POJO:Mail.java

[java] view plaincopy

1. public class Mail implements Serializable {  

2.    private static final long serialVersionUID = 7427977743354005783L;  

3.    private Integer id;  

4.    private String sender;  

5.    private String subject;  

6.    private String content;  

7.    private String fromAddress;  

8. ...  

9. getters and setters...  

10. }  

public class Mail implements Serializable {private static final long serialVersionUID = 7427977743354005783L;private Integer id;private String sender;private String subject;private String content;private String fromAddress;...getters and setters...}

Attachment.java

[java] view plaincopy

1. public class Attachment implements Serializable {  

2.    private static final long serialVersionUID = -1863183546552222728L;  

3.    private String id;  

4.    private String mailId;  

5.    private String name;  

6.    private String relativePath;  

7. ...  

8. getters and setters...  

9. }  

public class Attachment implements Serializable {private static final long serialVersionUID = -1863183546552222728L;private String id;private String mailId;private String name;private String relativePath;...getters and setters...} SqlMapConfig:

[html] view plaincopy

1. <?xml version="1.0" encoding="UTF-8"?>  

2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  

3. <configuration>  

4.    <properties resource="test/properties/mysql.properties"></properties>  

5.      

6.    <typeAliases>  

7.        <typeAlias type="test.model.Mail" alias="Mail"/>  

8.        <typeAlias type="test.model.Attachment" alias="Attachment"/>        

9.    </typeAliases>  

10.      

11.      

12.    <environments default="development">  

13.        <environment id="development">  

14.            <transactionManager type="JDBC" />  

15.            <dataSource type="UNPOOLED">  

16.                <property name="driver" value="${db_driver}" />  

17.                <property name="url" value="${db_url}" />  

18.                <property name="username" value="${db_user}" />  

19.                <property name="password" value="${db_password}"/>  

20.            </dataSource>  

21.        </environment>  

22.    </environments>    

23.          

24.    <mappers>  

25.    <mapper resource="test/data/MailMapper.xml"/>  

26.    <mapper resource="test/data/AttachmentMapper.xml"/>  

27.    </mappers>      

28. </configuration>  

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><properties resource="test/properties/mysql.properties"></properties><typeAliases><typeAlias type="test.model.Mail" alias="Mail"/><typeAlias type="test.model.Attachment" alias="Attachment"/></typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="UNPOOLED"> <property name="driver" value="${db_driver}" /> <property name="url" value="${db_url}" /> <property name="username" value="${db_user}" /> <property name="password" value="${db_password}"/> </dataSource> </environment> </environments> <mappers><mapper resource="test/data/MailMapper.xml"/><mapper resource="test/data/AttachmentMapper.xml"/> </mappers></configuration> MappersMailMapper.xml

[html] view plaincopy

1. <?xml version="1.0" encoding="UTF-8"?>  

2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  

3. <mapper namespace="test.data.MailMapper">  

4.    <cache />  

5.  

6.    <resultMap type="Mail" id="result_base">  

7.        <id property="id" column="id_mail" />  

8.        <result property="sender" column="sender"/>  

9.        <result property="fromAddress" column="from_address" />  

10.        <result property="subject" column="subject"/>  

11.        <result property="content" column="content"/>  

12.        <result property="sendTime" column="send_time" />  

13.            ....  

14.    </resultMap>  

15.    <!--这里是关键,一对多映射的“魔法”几乎都在<collection>的配置里。select=...中"test.data.AttachmentMapper"对应于AttachmentMapper中  

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="test.data.MailMapper"><cache /><resultMap type="Mail" id="result_base"><id property="id" column="id_mail" /><result property="sender" column="sender"/><result property="fromAddress" column="from_address" /><result property="subject" column="subject"/><result property="content" column="content"/><result property="sendTime" column="send_time" /> ....</resultMap><!--这里是关键,一对多映射的“魔法”几乎都在<collection>的配置里。select=...中"test.data.AttachmentMapper"对应于AttachmentMapper中

[html] view plaincopy

1.            的namespace-->  

2.    <resultMap type="Mail" id="result" extends="result_base">  

3.        <collection property="attachments" javaType="ArrayList" column="id_mail" ofType="Attachment"   

4.        select="test.data.AttachmentMapper.selectByMailId"/>  

5.    </resultMap>  

6.      

7.    <insert id="insert" parameterType="Mail" useGeneratedKeys="true" keyProperty="id_note">  

8.        insert into note(sender, from_address, subject, content, send_time)  

9.        values(#{sender}, #{fromAddress}, #{subject}, #{content}, #{sendTime})  

10.        <selectKey keyProperty="id_mail" resultType="int">   

11.                      select LAST_INSERT_ID()   

12.                </selectKey>   

13.    </insert>  

14.      

15.    <select id="selectById" parameterType="int" resultMap="result" >  

16.        select * from mail where id_mail = #{id}  

17.    </select>  

18.      

19.    <select id="selectAllMails" resultMap="result">  

20.        select * from note Note  

21.    </select>  

22.    <!--这里可以获得刚插入表格的id,为后面attachment的插入提供了mailId字段-->  

23.    <select id="selectLastId" resultType="int">  

24.         select LAST_INSERT_ID()   

25.    </select>  

26. </mapper>  

的namespace--><resultMap type="Mail" id="result" extends="result_base"><collection property="attachments" javaType="ArrayList" column="id_mail" ofType="Attachment" select="test.data.AttachmentMapper.selectByMailId"/></resultMap><insert id="insert" parameterType="Mail" useGeneratedKeys="true" keyProperty="id_note">insert into note(sender, from_address, subject, content, send_time)values(#{sender}, #{fromAddress}, #{subject}, #{content}, #{sendTime})<selectKey keyProperty="id_mail" resultType="int"> select LAST_INSERT_ID() </selectKey> </insert><select id="selectById" parameterType="int" resultMap="result" >select * from mail where id_mail = #{id}</select><select id="selectAllMails" resultMap="result">select * from note Note</select><!--这里可以获得刚插入表格的id,为后面attachment的插入提供了mailId字段--><select id="selectLastId" resultType="int"> select LAST_INSERT_ID() </select></mapper> AttachmentMapper.xml

[html] view plaincopy

1. <?xml version="1.0" encoding="UTF-8"?>  

2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  

3. <mapper namespace="test.data.AttachmentMapper">  

4.    <cache />  

5.      

6.    <resultMap type="Attachment" id="result">  

7.        <result property="id" column="id_accessory" />  

8.        <result property="name" column="name" />  

9.        <result property="relativePath" column="relative_path" />  

10.        <result property="mailId" column="id_mail" />  

11.    </resultMap>  

12.      

13.    <insert id="insert" parameterType="Attachment">  

14.        insert into attachments(id_mail, name, relative_path) values(#{mailId}, #{name}, #{relativePath})  

15.    </insert>  

16.    <!--MailMapper中的ResultMap调用这个方法来进行关联-->  

17.    <select id="selectByMailId" parameterType="int" resultMap="result">  

18.        select  id, id_mail, name, relative_path  

19.         from attachments where id_note = #{id}  

20.    </select>  

21. </mapper>  

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="test.data.AttachmentMapper"><cache /><resultMap type="Attachment" id="result"><result property="id" column="id_accessory" /><result property="name" column="name" /><result property="relativePath" column="relative_path" /><result property="mailId" column="id_mail" /></resultMap><insert id="insert" parameterType="Attachment">insert into attachments(id_mail, name, relative_path) values(#{mailId}, #{name}, #{relativePath})</insert><!--MailMapper中的ResultMap调用这个方法来进行关联--><select id="selectByMailId" parameterType="int" resultMap="result">select id, id_mail, name, relative_path from attachments where id_note = #{id}</select></mapper>

DAO

AttachmentDAO

[java] view plaincopy

1. public class AttachmentDAO {  

2.    private SqlSessionFactory sqlSessionFactory;  

3.      

4.    public AttachmentDAO(){  

5.        this.sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory();  

6.    }  

7.      

8.    public void insert(Attachment attachment){  

9.             SqlSession session = sqlSessionFactory.openSession();  

10.             AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class);   

11.             try {  

12.                attachmentMapper.insert(attachment);  

13.                session.commit();  

14.             } finally {  

15.                session.close();  

16.             }  

17.    }  

18. }  

public class AttachmentDAO {private SqlSessionFactory sqlSessionFactory;public AttachmentDAO(){this.sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory();}public void insert(Attachment attachment){ SqlSession session = sqlSessionFactory.openSession(); AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class); try { attachmentMapper.insert(attachment); session.commit(); } finally { session.close(); }}}

MailDAO

[java] view plaincopy

1. public class MailDAO {  

2.    private SqlSessionFactory sqlSessionFactory;  

public class MailDAO { private SqlSessionFactory sqlSessionFactory;

[java] view plaincopy

1. public MailDAO(){  

2.    sqlSessionFactory = TestConnectionFactory.getSqlSessionFactory();  

3. }   

4.  

5. public void insertMailOnly(Mail mail){  

6.    SqlSession session = sqlSessionFactory.openSession();  

7.    MailMapper mailMapper = session.getMapper(MailMapper.class);  

8.    try {  

9.        mailMapper.insert(mail);         

10.        session.commit();  

11.    } finally {  

12.        session.close();  

13.    }  

14. }   

15. //inset   

16. public void insertMail(Mail mail){  

17.    SqlSession session = sqlSessionFactory.openSession();  

18.    MailMapper mailMapper = session.getMapper(MailMapper.class);  

19.    AttachmentMapper attachmentMapper = session.getMapper(AttachmentMapper.class);  

20.      

21.    try{  

22.    mailMapper.insert(mail);  

23.    //这里必须commit,再执行Attachment的插入操作。否则会导致null pointer异常  

24.    session.commit();  

25.    //获得最近插入到note表的id  

26.    int mailId = mailMapper.selectLastId();  

27.    for(Attachment attach : mail.getAttachments()){  

28.        attach.setMailId(String.valueOf(mailId));  

29.        attachmentMapper.insert(attach);  

30.    }  

31.    session.commit();  

32.    }finally{  

33.        session.close();  

34.    }  

35. }  

36.  

37. public ArrayList<Mail> selectAllMails(){        

38.    ArrayList<Mail> mailList = null;  

39.    SqlSession session = sqlSessionFactory.openSession();  

40.    MailMapper mailMapper = session.getMapper(MailMapper.class);  

41.    try {             

42.        mailList = mailMapper.selectAllMails();  

43.        session.commit();  

44.    } finally {  

45.        session.close();  

46.    }  

47. urn mailList;  

48. }   

49.  

50. public Mail selectMailById(int i){  

51.    Mail mail = null;  

52.    SqlSession session = sqlSessionFactory.openSession();  

53.    MailMapper mailMapper = session.getMapper(MailMapper.class);  

54.    try {             

55.        mail = mailMapper.selectById(i);  

56.        session.commit();  

57.    } finally {  

58.        session.close();  

59.    }  

60. urn mail;  

61. }  

62.  

63. public int selectLastId(){  

64.    int id = -1;  

65.    SqlSession session = sqlSessionFactory.openSession();  

66.    MailMapper mailMapper = session.getMapper(MailMapper.class);  

67.    try {             

68.        id = mailMapper.selectLastId();  

69.        session.commit();  

70.    } finally {  

71.        session.close();  

72.    }  

73. urn id;  

74. }  


7.

8.

9.


转载于:https://my.oschina.net/looten/blog/306577

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值