mybatis_user_guide(6) Java API

来源:互联网 发布:python实现矩阵相乘 编辑:程序博客网 时间:2024/06/16 00:26
【0】README
1)本文全文总结于 http://www.mybatis.org/mybatis-3/zh/java-api.html

【1】SqlSessions
1)intro: 我们知道, SqlSessionFactoryBuilder 创建 SqlSessionFactory , SqlSessionFactory 创建 SqlSession,然后 SqlSession 获得映射器,而映射器可以执行 sql 语句映射的方法,从而达到与数据库交互的目的;

【1.1】SqlSessionFactoryBuilder
1)SqlSessionFactoryBuilder 有五个 build()方法,每一种都允许你从不同的资源中创建一个 SqlSession 实例。
SqlSessionFactory build(InputStream inputStream)SqlSessionFactory build(InputStream inputStream, String environment)SqlSessionFactory build(InputStream inputStream, Properties properties)SqlSessionFactory build(InputStream inputStream, String env, Properties props)SqlSessionFactory build(Configuration config)
对以上代码的分析(Analysis): Environment 决定加载哪种环境,包括数据源和事务管理器。比如:
<environments default="development">  <environment id="development">    <transactionManager type="JDBC">        ...    <dataSource type="POOLED">        ...  </environment>  <environment id="production">    <transactionManager type="MANAGED">        ...    <dataSource type="JNDI">        ...  </environment></environments>
2) 如果一个属性存在于这些位置,那么 MyBatis 将会按找下面的顺序来加载它们:
  • 在 properties 元素体中指定的属性首先被读取,
  • 从 properties 元素的类路径 resource 或 url 指定的属性第二个被读取, 可以覆盖已经 指定的重复属性,
  • 作为方法参 数传递 的属性最 后被读 取,可以 覆盖已 经从 properties 元 素体和 resource/url 属性中加载的任意重复属性。

      因此,最高优先级的属性是通过方法参数传递的,之后是 resource/url 属性指定的,最 后是在 properties 元素体中指定的属性。(干货——属性设置的优先级)

Conclusion)  总结一下,前四个方法很大程度上是相同的,但是由于可以覆盖,就允许你可选地指定 environment 和/或 properties。 这里给出一个从 mybatis-config.xml 文件创建 SqlSessionFactory 的示例:(干货——从 mybatis-config.xml 文件创建 SqlSessionFactory 的示例)

String resource = "org/mybatis/builder/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(inputStream);

3)以上代码用到了Resources 工具类,这个类在 org.mybatis.io 包中。Resources 类正 如其名,会帮助你从类路径下,文件系统或一个 web URL 加载资源文件。其方法列表如下:
URL getResourceURL(String resource)URL getResourceURL(ClassLoader loader, String resource)InputStream getResourceAsStream(String resource)InputStream getResourceAsStream(ClassLoader loader, String resource)Properties getResourceAsProperties(String resource)Properties getResourceAsProperties(ClassLoader loader, String resource)Reader getResourceAsReader(String resource)Reader getResourceAsReader(ClassLoader loader, String resource)File getResourceAsFile(String resource)File getResourceAsFile(ClassLoader loader, String resource)InputStream getUrlAsStream(String urlString)Reader getUrlAsReader(String urlString)Properties getUrlAsProperties(String urlString)Class classForName(String className)
4)看个荔枝: 如何手动配置 configuration 实例,然后将它传递给 build()方法来创建 SqlSessionFactory
DataSource dataSource = BaseDataTest.createBlogDataSource();TransactionFactory transactionFactory = new JdbcTransactionFactory();Environment environment = new Environment("development", transactionFactory, dataSource);Configuration configuration = new Configuration(environment);configuration.setLazyLoadingEnabled(true);configuration.setEnhancementEnabled(true);configuration.getTypeAliasRegistry().registerAlias(Blog.class);configuration.getTypeAliasRegistry().registerAlias(Post.class);configuration.getTypeAliasRegistry().registerAlias(Author.class);configuration.addMapper(BoundBlogMapper.class);configuration.addMapper(BoundAuthorMapper.class);SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(configuration);

【1.2】SqlSessionFactory
1)intro: SqlSessionFactory 有六个方法可以用来创建 SqlSession 实例。通常来说,如何决定是你 选择下面这些方法时:
  • Transaction (事务):你想为 session 使用事务或者使用自动提交(通常意味着很多 数据库和/或 JDBC 驱动没有事务)?
  • Connection (连接):你想 MyBatis 获得来自配置的数据源的连接还是提供你自己
  • Execution (执行):你想 MyBatis 复用预处理语句和/或批量更新语句(包括插入和 删除)?

2) 重载的 openSession()方法签名设置允许你选择这些可选中的任何一个组合。
SqlSession openSession()SqlSession openSession(boolean autoCommit)SqlSession openSession(Connection connection)SqlSession openSession(TransactionIsolationLevel level)SqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)SqlSession openSession(ExecutorType execType)SqlSession openSession(ExecutorType execType, boolean autoCommit)SqlSession openSession(ExecutorType execType, Connection connection)Configuration getConfiguration();
对以上代码的分析(Analysis):

A1)默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:

  • 会开启一个事务(也就是不自动提交)
  • 连接对象会从由活动环境配置的数据源实例中得到。
  • 事务隔离级别将会使用驱动或数据源的默认设置。
  • 预处理语句不会被复用,也不会批量处理更新。
A2) 还有一个可能对你来说是新见到的参数,就是 ExecutorType。这个枚举类型定义了 3 个 值:
  • ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
  • ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
  • ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。
Attention)
A1)getConfiguration()方法:会返回一个 Configuration 实例,在运行时你可以使用它来自检 MyBatis 的配置。
A2)如果你已经使用之前版本 MyBatis,你要回忆那些 session,transaction 和 batch 都是分离的。现在和以往不同了,这些都包含在 session 的范围内了。你需要处理分开处理 事务或批量操作来得到它们的效果。

【1.3】SqlSession
1)intro: 在 SqlSession 类中有超过 20 个方法,所以将它们分开成易于理解的组合。

【1.3.1】语句执行方法
1)intro: 这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT,INSERT,UPDA E T 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以 是原生类型(自动装箱或包装类) ,JavaBean,POJO 或 Map。(干货——sql 语句需要参数的case)
<T> T selectOne(String statement, Object parameter)<E> List<E> selectList(String statement, Object parameter)<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)int insert(String statement, Object parameter)int update(String statement, Object parameter)int delete(String statement, Object parameter)
对以上代码的分析(Analysis): selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象。 如果多余一个, 或者 没有返回 (或返回了 null) 那么就会抛出异常。 , 如果你不知道需要多少对象, 使用 selectList。

2)如果你想检查一个对象是否存在,那么最好返回统计数(0 或 1) 。因为并不是所有语句都需 要参数,这些方法都是有不同重载版本的,它们可以不需要参数对象。(干货——sql 语句不需要参数的case)
<T> T selectOne(String statement)<E> List<E> selectList(String statement)<K,V> Map<K,V> selectMap(String statement, String mapKey)int insert(String statement)int update(String statement)int delete(String statement)
3)最后,还有查询方法的三个高级版本:它们允许你限制返回行数的范围,或者提供自定 义结果控制逻辑,这通常用于大量的数据集合。
<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)void select (String statement, Object parameter, ResultHandler<T> handler)void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)
对以上代码的分析(Analysis):
A1)RowBounds 参数会告诉 MyBatis 略过指定数量的记录,还有限制返回结果的数量。 RowBounds 类有一个构造方法来接收 offset 和 limit,否则是不可改变的。(干货——引入 RowBounds 参数)
int offset = 100;int limit = 25;RowBounds rowBounds = new RowBounds(offset, limit);
A2) ResultHandler 参数允许你按你喜欢的方式处理每一行。你可以将它添加到 List 中,创 建 Map, 或抛出每个结果而不是只保留总计。 Set 你可以使用 ResultHandler 做很多漂亮的事, 那就是 MyBatis 内部创建结果集列表。它的接口很简单。
package org.apache.ibatis.session;public interface ResultHandler<T> {  void handleResult(ResultContext<? extends T> context);}

【1.3.2】Batch update statement Flush Method

1)intro: There is method for flushing(executing) batch update statements that stored in a JDBC driver class at any timing. This method can be used when you use the ExecutorType.BATCH as ExecutorType.

List<BatchResult> flushStatements()

【1.3.3.】 事务控制方法

1)intro: 控制事务范围有四个方法。 当然, 如果你已经选择了自动提交或你正在使用外部事务管 理器,这就没有任何效果了。然而,如果你正在使用 JDBC 事务管理员,由 Connection 实 例来控制,那么这四个方法就会派上用场:

void commit()void commit(boolean force)void rollback()void rollback(boolean force)

Attention) 默认情况下 MyBatis 不会自动提交事务, 除非它侦测到有插入, 更新或删除操作改变了 数据库。如果你已经做出了一些改变而没有使用这些方法,那么你可以传递 true 到 commit 和 rollback 方法来保证它会被提交(注意,你不能在自动提交模式下强制 session,或者使用 了外部事务管理器时) 。很多时候你不用调用 rollback(),因为如果你没有调用 commit 时 MyBatis 会替你完成。然而,如果你需要更多对多提交和回滚都可能的 session 的细粒度控 制,你可以使用回滚选择来使它成为可能。(干货—— 默认情况下 MyBatis 不会自动提交事务, 除非它侦测到有插入, 更新或删除操作改变了 数据库。)

【1.3.4】清理 Session 级的缓存
void clearCache()
对以上代码的分析(Analysis): SqlSession 实例有一个本地缓存在执行 update,commit,rollback 和 close 时被清理。要 明确地关闭它(获取打算做更多的工作) ,你可以调用 clearCache()。

【1.3.5】 确保 SqlSession 被关闭
1)intro:
void close()

2)你必须保证的最重要的事情是: 你要关闭所打开的任何 session。保证做到这点的最佳方 式是下面的工作模式:(干货——关闭打开的任何 Session)

SqlSession session = sqlSessionFactory.openSession();try {    // following 3 lines pseudocod for "doing some work"    session.insert(...);    session.update(...);    session.delete(...);    session.commit();} finally {    session.close();}

2.1)还有,如果你正在使用jdk 1.7以上的版本还有MyBatis 3.2以上的版本,你可以使用try-with-resources语句:(干货——使用带资源的 try 语句)

try (SqlSession session = sqlSessionFactory.openSession()) {    // following 3 lines pseudocode for "doing some work"    session.insert(...);    session.update(...);    session.delete(...);    session.commit();}

Attention)就像 SqlSessionFactory,你可以通过调用 getConfiguration()方法获得 SqlSession 使用的 Configuration 实例

Configuration getConfiguration()

【1.4】使用映射器(推荐使用映射器和数据库交互
<T> T getMapper(Class<T> type)

1)intro:上述的各个 insert,update,delete 和 select 方法都很强大,但也有些繁琐,没有类型安 全,对于你的 IDE 也没有帮助,还有可能的单元测试。在上面的入门章节中我们已经看到 了一个使用映射器的示例。

2)因此, 一个更通用的方式来执行映射语句是使用映射器类。 一个映射器类就是一个简单 的接口,其中的方法定义匹配于 SqlSession 方法。下面的示例展示了一些方法签名和它们是 如何映射到 SqlSession 的。

public interface AuthorMapper {  // (Author) selectOne("selectAuthor",5);  Author selectAuthor(int id);   // (List<Author>) selectList(“selectAuthors”)  List<Author> selectAuthors();  // (Map<Integer,Author>) selectMap("selectAuthors", "id")  @MapKey("id")  Map<Integer, Author> selectAuthors();  // insert("insertAuthor", author)  int insertAuthor(Author author);  // updateAuthor("updateAuthor", author)  int updateAuthor(Author author);  // delete("deleteAuthor",5)  int deleteAuthor(int id);}

【1.4.1】映射器注解
1)intro: 注解提供了一种简单的方式来实现简单映射语句,而 不会引入大量的开销;

【1.4.2】 映射声明样例
 荔枝1)intro: 这个例子展示了如何使用 @SelectKey 注解来在插入前读取数据库序列的值:
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)int insertTable3(Name name);
荔枝2)这个例子展示了如何使用 @SelectKey 注解来在插入后读取数据库识别列的值:
@Insert("insert into table2 (name) values(#{name})")@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)int insertTable2(Name name);

荔枝3)This example shows using the @Flush annotation to call the SqlSession#flushStatements():

@FlushList<BatchResult> flush();

荔枝4)These examples show how to name a ResultMap by specifying id attribute of @Results annotation.

@Results(id = "userResult", value = {  @Result(property = "id", column = "uid", id = true),  @Result(property = "firstName", column = "first_name"),  @Result(property = "lastName", column = "last_name")})@Select("select * from users where id = #{id}")User getUserById(Integer id);@Results(id = "companyResults")@ConstructorArgs({  @Arg(property = "id", column = "cid", id = true),  @Arg(property = "name", column = "name")})@Select("select * from company where id = #{id}")Company getCompanyById(Integer id);

荔枝5)This example shows solo parameter using the Sql Provider annotation:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")List<User> getUsersByName(String name);class UserSqlBuilder {  public String buildGetUsersByName(final String name) {    return new SQL(){{      SELECT("*");      FROM("users");      if (name != null) {        WHERE("name like #{value} || '%'");      }      ORDER_BY("id");    }}.toString();  }}

荔枝6)This example shows multiple parameters using the Sql Provider annotation:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")List<User> getUsersByName(    @Param("name") String name, @Param("orderByColumn") String orderByColumn);class UserSqlBuilder {  // If not use @Param, you should be define same arguments with mapper method  public String buildGetUsersByName(      final String name, final String orderByColumn) {    return new SQL(){{      SELECT("*");      FROM("users");      WHERE("name like #{name} || '%'");      ORDER_BY(orderByColumn);    }}.toString();  }  // If use @Param, you can define only arguments to be used  public String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {    return new SQL(){{      SELECT("*");      FROM("users");      WHERE("name like #{name} || '%'");      ORDER_BY(orderByColumn);    }}.toString();  }}


0 0