MyBatis是一款能自定义sql和映射的持久层框架,摒除了大量的JDBC代码、手工设置参数和结果集封装,提高了开发效率。
1、SqlSessionFactory
SqlSessionFactory类是获取SqlSession对象的工厂类,实现代码如下:
String resource = config文件的路径(由开发人员编写);
Reader reader =Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
config文件的内容如下所示,当然只是举个例子,开发人员必须根据自己的开发环境编写对应的数据
<?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对象
<configuration>
--- 表示默认采用id="development"的environment 配置
<environments default="development">
<environment id="development">
---事务管理
<transactionManager type="JDBC"/>
---采用数据库连接池操作DB
<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>
---预定义要加载的映射文件
<mappers>
<mapper resource="org/mybatis/example/mapper1.xml"/>
</mappers>
</configuration>
获取SqlSessionFactory的源码对应SqlSessionFactoryBuilder类中的build()方法:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//将config配置文件的信息封装到XMLConfigBuilder对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
其中parser.parse()方法的源码如下所示:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each MapperConfigParser can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration")); //这句很重要
return configuration;
}
private void parseConfiguration(XNode root) {
try {
---读取config文件中<properties></properties>标签里的内容
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
---读取config文件中<typeAliases></typeAliases>标签里的内容
typeAliasesElement(root.evalNode("typeAliases"));
---读取config文件中<plugins></plugins>标签里的内容
pluginElement(root.evalNode("plugins"));
---读取config文件中<objectFactory></objectFactory>标签里的内容
objectFactoryElement(root.evalNode("objectFactory"));
---读取config文件中<objectWrapperFactory></objectWrapperFactory>标签里的内容
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
----读取config文件中<settings></settings>标签里的内容
settingsElement(root.evalNode("settings"));
---读取config文件中的<environments></environments>标签里的内容
environmentsElement(root.evalNode("environments"));
---读取config文件中的<databaseIdProvider ></databaseIdProvider >标签里的内容
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
---读取config文件中的<typeHandlers ></typeHandlers >标签里的内容,用于自定义数据类型转换
typeHandlerElement(root.evalNode("typeHandlers"));
---读取config文件中的< mappers></mappers >标签里的内容,获取配置的映射文件
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
2、获取SqlSession对象
如果你有一个SqlSessionFactory,你就可以来获取一个SqlSession实例,SqlSession包含了针对数据库执
行语句的每一个方法。你可以直接使用SqlSession执行已经映射的每一个SQL语句。比如:
SqlSession session =ssf.openSession();
try {
Blog blog = session.select("org.mybatis.example.BlogMapper.selectBlog ", 101);
} finally {
session.close();
}
除此之外,还可以通过接口的方式操纵数据库,代码如下:
SqlSession session =sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
接下来就是编写BlogMapper对应的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="org.mybatis.example.BlogMapper">
<select id="selectBlog" parameterType="int" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
在上面的代码中在方法调用完后,必须关闭openSession对象,避免数据库资源一直被占用。
3、高级结果查询
(1)、一对一查询简单查询(association)
<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
---blog表和author表关联查询,将author表中的查询结果封装到Author对象,同时将Author对象赋值给blog对---象的author属性,也可在association标签中设置select=”selectAuthor”属性,表示结果集从selectAuthor---方法读取
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
</association>
</resultMap>
constructor–用来将结果反射给一个实例化好的类的构造器
idArg –ID参数;将结果集标记为ID,以方便全局调用
arg –反射到构造器的通常结果
id –ID结果,将结果集标记为ID,以方便全局调用
result –反射到JavaBean属性的普通结果
association –复杂类型的结合;多个结果合成的类型
(2)、识别器查询(discriminator)
将上述的配置
<resultMap id="vehicleResult" type="Vehicle">
<id property=”id”column="id" />
<result property="vin" column="vin"/>
<result property="year" column="year"/>
<result property="color" column="color"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultMap="carResult"/>
<case value="2" resultMap="truckResult"/>
<case value="3" resultMap="vanResult"/>
<case value="4" resultMap="suvResult"/>
</discriminator>
</resultMap>
MyBatis将会从数据集中获取每条记录,并比较vehicletype的值。如果它匹配了识别器的条件,就会使用相对应的resultMap。
(3)、一对多查询(collection )
<resultMap id="blogResult" type="Blog">
<id property=”id”column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
collection标签表示:一组名为posts的ArrayList集合,它的类型是Post。javaType 属于完全可以省略,MyBatis会为你自动识别。
4、foreach动态SQL语句(参数为list、array等集合类型)
<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>
foreach元素非常强大,允许你指定一个集合,申明一个项和一个索引变量,用在这个元素的方法体内。也允许你指定开始和结束的字符,也可以在两个迭代器之间加入一个分隔符。它的智能之处在于它不会偶尔追加额外的分隔符。
注意:你可以传入一个List实例或者一个数组给MyBatis作为一个参数对象。如果你这么做,MyBatis会自动将它包装成一个Map,使用它的名称做为key。List实例将使用“list”做为键,数组实例以“array”作为键。
5、@InsertProvider使用
这是可选的SQL注解,允许你在运行的过程中,指定类名和方法名返回SQL来执行。。属性:type,method。type属性指定类的全名,method方法属性指定方法名称。
6、@InsertProvider结合SqlBuilder
mapper接口类的代码如下:
@InsertProvider(method = "insert", type = MySqlBuilder.class)
public Integer insert(UserType entity);
MySqlBuilder类的代码如下:
import static org.apache.ibatis.jdbc.SelectBuilder.BEGIN;
import static org.apache.ibatis.jdbc.SqlBuilder.*;
public class MySqlBuilder {
public String insert() {
BEGIN();
INSERT_INTO(TABLE_NAME);
VALUES("value", "#{value}");
return SQL();
}
} |