mybatis之JAVA API

来源:互联网 发布:单片机系统电路原理图 编辑:程序博客网 时间:2024/06/06 02:48

现在你知道了如何配置MyBatis 和创建映射,你已经准备好工作了。MyBatis Java API 是你获取你努力的报酬的地方。正如你将看到的,于JDBC相比较,MyBatis 在很大程度上简化了你的代码,使代码保持整洁,很容易理解和维护。MyBatis 3为了促使SQL Maps更好的运行已经引入了大量有意义的改善。
目录结构
在我们沉溺于Java API之前,最好理解目录结构周围的练习是很重要的。MyBatis 是很灵活的,而且你可以做任何的事情通过你的文件。但和其他框架相比,这里有个更好的方式。
让我们来看一下这个典型应用的目录结构:

/my_application  /bin  /devlib  /lib                <-- MyBatis *.jar files go here.  /src    /org/myapp/      /action      /data           <-- MyBatis artifacts go here, including, Mapper Classes, XML Configuration, XML Mapping Files.        /mybatis-config.xml        /BlogMapper.java        /BlogMapper.xml      /model      /service      /view    /properties       <-- Properties included in your XML Configuration go here.  /test    /org/myapp/      /action      /data      /model      /service      /view    /properties  /web    /WEB-INF      /web.xml

记住,这些都是首选项,不是必须项,但是其他人会感谢你,因为你使用了一个通用的目录结构。
这部分的剩下例子中,我们假设你会遵循这个目录结构。
SqlSession
MyBatis 运行的最初JAVA接口是SqlSession。通过这个接口你可以执行命令,得到映射和管理事务。马上我们就会讨论更多关于SqlSession 的知识。但是我们首先需要学习如何获得一个SqlSession的实例。SqlSession是被 SqlSessionFactory 的一个实例所创建的。SqlSessionFactory 包含了创建SqlSession实例的所有不同的方式。SqlSessionFactory 是被SqlSessionFactoryBuilder 创建的,SqlSessionFactoryBuilder 是可以通过XML,注解或者手工编写的JAVA配置来创建SqlSessonFactory 。
注意:当把MyBatis 和一个依赖注入的框架(Spring ,Guice)结合使用,SqlSessions 被通过依赖注入框架创建和注入,所以你不需要使用
SqlSessionFactoryBuilder 或者SqlSessionFactory ,而且你可以直接去SqlSession 的部分。请查阅MyBatis-Spring或者MyBatis-Guice说明书获取更多的信息。
SqlSessionFactoryBuilder
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)

前面四个方法是最常见的,正如他们采用了InputStream 的实例,引用XML文档或者更多明确的,mybatis-config.xml 文件被发现。可选的参数是环境和属性。环境决定了环境加载,包含了数据源和事务管理。比如:

<environments default="development">  <environment id="development">    <transactionManager type="JDBC">        ...    <dataSource type="POOLED">        ...  </environment>  <environment id="production">    <transactionManager type="MANAGED">        ...    <dataSource type="JNDI">        ...  </environment></environments>

如果你调用了一个build方法,这个方法用了environment 参数,然后MyBatis 将会使用那个environment的配置。当然,如果你指定一个无效的环境,你将会收到一个错误。如果你调用了build方法中没有采用环境参数的那个,接着默认的环境就会起作用。(在上面的例子中被指定为默认的那个default=”development”)
如果你调用了一个带有properties 实例的方法,接着MyBatis 会加载这些properties ,并且使他们对于你的配置是可以利用的。这些properties 可以被使用来替代在配置中使用大量的语法:${propName}
记得,属性也可以从mybatis-config.xml文件引用,或直接指定范围内。因此对于理解优先级是很重要的。我们在这篇文档中提到的优先级都是比较简单的,但是这里有一个简单的文章参考:
如果有个属性在这些地方之一存在,MyBatis 就会按照下面的顺序加载它们。
首先读取属性元素中指定的属性.
其次读取路径资源或者URL中的属性元素中的属性被加载,重写已经存在的重复指定的属性。
最后属性被当做方法参数来读取,并且重写那些重复或许已经在属性元素中或者资源或者URL中加载的属性。因此,最高优先级的属性是那些被当做方法参数的属性,接下来是资源或者URL中的,最后是属性元素中指定的属性。
总的来说,前四种方法大体相同,但是重写允许你随意地指定环境和属性。下面是一个从 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);

注意:我们正在使用Resources 工具类,这个工具类存在org.apache.ibatis.io包中。Resources 正如它的名字的意思,帮助你从路径,文件系统或者web URL中加载资源。用你的IDE工具来看看你这个类的源代码,它会很明白的展示一系列很有用的方法,下面是个简易列表:

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)

最后一个build方法采用了一个配置的实例,这个配置类包含你可能了解关于SqlSessionFactory 实例的所有信息。这个配置类对于了解配置是很有用的,它包含了寻找和操作SQL maps(一旦应用程序接受请求就不推荐了)。该配置类有你已经学到的所有配置开关,仅仅被当做JAVA API暴露。这里有一个如何手工的配置实例并且把它传递给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);

现在你有一个SqlSessionFactory 被用来创建SqlSession 的实例。
SqlSessionFactory
SqlSessionFactory 有6个方法可以被用来创建SqlSession 的实例。一般来说,当您选择这些方法之一时,您将作出的决定是:
事务:你想在session中使用事务范围?使用自动提交?(通常大多数没有事务的数据库或者JDBC驱动)。
连接:你想让MyBatis 通过你配置的一个数据源获得一个连接?还是你想提供自己的?
执行:你想让MyBatis 重新使用PreparedStatement或者是批量更新(包含插入和删除)?
一系列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();

默认的openSession方法是没有参数的,他可以通过下面的特性创建SqlSession:
将启动一个事务范围(例如:不是自动提交)
在激活的环境中通过配置数据源的实例来获得一个Connection 对象。
事务的隔离级别会被驱动或者数据源默认使用。
没有PreparedStatement会被重复使用,没有更新会被批量处理。
大多数的方法相当明白。为了可以自动提交,传递一个真实的值给自动提交的参数。为了提供你自己的链接,传递一个Connection 的实例给链接参数。注意,这里没有重写来设置Connection 和autoCommit因为MyBatis 将使用正在使用的设置所提供的连接对象。MyBatis 使用java的枚举包装事务隔离层次,被称为事务隔离级别,但是它们正如所预期那样的工作,并且有五种被JDBC所支持的级别(NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE)。
对你来说ExecutorType这个参数可能是一个新的。这个枚举定义了3种值:
ExecutorType.SIMPLE: 这个类型的executor 是普通的。它为每一个语句的执行创建了一个新的PreparedStatement 。
ExecutorType.REUSE: 这个类型的executor将会重复使用PreparedStatement。
ExecutorType.BATCH: 这个executor将批量更新所有的语句,并且如果选择时必要的则在执行的时候区分它们,目的是确保一个简单容易理解的行为。
注意:这里有更多关于SqlSessionFactory 的方法,但是我们没有 提到,比如getConfiguration方法。这个方法会返回一个配置的实例,你可以使用内测在MyBatis 运行时配置。
如果你使用的是MyBatis以前的版本,你将会重新调用sessions,transactions ,而且所有的事情都会被批量隔离。但是这里不存在这样的例子。三个都会被整体的包含在一个session范围内。你不需要处理事务或者批量隔离来获取最大好处。
SqlSession
正如所提到的,在MyBatis中SqlSession 实例是很重要的。你将寻找所有的方法来执行语句,提交或者回滚事务和获得映射实例时,它都会出现。
在SqlSession 的类中有超过20多种的方法,所以让我们把他们进行打乱分组,便于我们掌握这些方法。
语句执行方法
这些方法被用来执行在你的SQL映射XML中定义的SELECT, INSERT, UPDATE 和DELETE 语句,每个语句都会采用语句的ID和参数对象,这些可以被当做原始的(自动打包或者解包),一个JavaBean,一个POJO或者一个Map。

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

selectOne 和selectList之间的差别只在于:selectOne 必须返回一个确切的对象或者null。如果有其他的情况,如果你使用selectList,但是不知道预期有多少对象,就会抛出一个异常。如果你想检查一个对象是否存在,你最好返回一个(0或者1)。selectMap 是一个特殊的例子,它的设计就是将基于在对象结果的所有属性中把一个结果集转换为一个map。因为并不是所有的语句都需要一个参数,这些方法以不同的版本被重载,而且没有对参数对象做要求。
通过nsert, update和delete方法来返回一个值,说明这个语句影响了多少行记录。

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

最后,这里有select更加高级的三种方法,允许你限制返回的行范围,或者提供定制的结果处理逻辑,通常对于非常大的数据结果集。

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

参数RowBounds 可以使MyBatis 跳过记录具体的行数,和限制结果返回行号一样。MyBatis 类有一个构造方法,用来采用限制和抵消,否则就是不可变的。

int offset = 100;int limit = 25;RowBounds rowBounds = new RowBounds(offset, limit);

不同的驱动可以在这方面实现不同的效率级别。最好的就是,使用SCROLL_SENSITIVE 或者SCROLL_INSENSITIVE 的结果类型(换句话说:不是FORWARD_ONLY)。
参数ResultHandler 允许你可以处理你想处理的行。你可以把它添加到一个list,创建一个Map,Set,或者扔掉每个结果,相反保持计算结果的总数的出现。你可以通过ResultHandler做很多的事情,这就是MyBatis使用内部本身建立的结果集列表。
这个接口是非常简单的。

package org.apache.ibatis.session;public interface ResultHandler<T> {  void handleResult(ResultContext<? extends T> context);}

参数ResultContext可以让你访问结果对象本身,创建的结果对象的数量的总数,一个Boolean类型的stop()方法,你可以使用它来停止MyBatis中正在加载的任何结果集 。
你必须意识到,使用ResultHandler 有两个限制:
得到数据是通过一个带有ResultHandler 的方法调用,并且不会缓存。
当使用高级的resultmaps时,MyBatis 或许将会要求一些行来创建对象。如果一个ResultHandler被使用,可能会给你一个没有联系或者集合至今没有被填充的对象。
批量更新语句 Flush方法
这是一个执行批量更新语句的方法。在任何情况下,它可以被存储在JDBC的驱动类中。当你使用ExecutorType.BATCH作为Executor类型的时候这个方法会被使用。

List<BatchResult> flushStatements()

事务控制方法:
这里有4个方法来控制事务的范围。当然,如果你选择自动提交或者你正在使用内部的事务管理也是没有影响的。然后,如果你正在使用JDBC事务管理,通过Connection 的实例来管理,那么下面的四种方法就会派上用场:

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

MyBatis默认是不会实际提交的,除非你发现数据库已经通过调用insert,update或者delete发生了改变。如果你以某种方式改变了,但是没有调用这些方法,你可以在commit或者rollback方法中传递一个true参数来保证它会被提交(注意:你仍然不可以强迫一个session到你的自动提交模型中,或者正在使用的内部事务管理)。大多数时间不必须调用rollback方法,如果你不调用commit方法,作为MyBatis 将会那样为你调用。然而,如果你需要在多个提交和回滚中有更好的细粒度的控制session,你可以让rollback选择这里成为可能性。
注意: MyBatis-Spring和MyBatis-Guice提供了一个公开的事务处理。所以如果你使用MyBatis -Spring或者MyBatis -Guice,请查阅更多他们自己的手册。
本地缓存
MyBatis 使用了两种缓存:一个是本地缓存,另一个是二级缓存。
每次新创建一个session时,MyBatis 会创建一个本地缓存,并且把它附在session上。任何含有session的查询执行会被存储在本地缓存,所以以后同样输入参数的查询被执行 时,不会先从数据库中找,本地缓存被清楚取决于更新,提交,回滚和关闭。
在整个session存活期间,默认的使用了本地缓存数据。这个缓存解决了循环引用和加速重复嵌套的查询,所以它永远不会无效。但是你可以通过设置localCacheScope=STATEMENT来配置使用本地缓存,只在执行语句期间。
注意:当本地缓存范围被设置为session时,对于相同的对象,MyBatis 会返回被存储在本地缓存中的引用。任何返回对象的修改影响本地缓存目录,并且随后在session的生命周期的缓存中返回值。因此,作为最好的实践,不要通过MyBatis修改对象来返回。
你可以在任何时间调用时清理本地缓存:

void clearCache()

确定SqlSession 被关闭了。

void close()

最重要的事情就是你必须确定你关闭了你打开的所有session。最好的方式确定使用下面的工作模式的单元:

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

Or, If you are using jdk 1.7+ and MyBatis 3.2+, you can use the try-with-resources statement:
或者,如果你正在使用JDK1.7以上的版本和MyBatis 3.2以上的版本,你可以使用try-with-resources语句:

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

就像SqlSessionFactory,你可以得到通过调用getConfiguration方法的SqlSession 配置的实例:

Configuration getConfiguration()

使用映射:

<T> T getMapper(Class<T> type)

当不同的insert,update,delete和select出现,它们是很繁琐的,不是类型安全的,并且对你的IDE或者单元测试也没有多大用处。在开始的模块中我们已经看到了一个使用映射的例子。
因此,一个共通的方式来执行映射语句是使用Mapper类。一个映射类简化一个带有方法定义的接口,来匹配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);}

一言以蔽之,每个映射方法签名应该匹配它有关联的SqlSession 方法,但是没有String 类型的参数ID。相反,方法名字必须匹配映射的语句ID。
此外,返回的类型必须匹配每个单独结果或者数据或者多个结果集的集合所期待的结果类型。所有常用的类型都是被支持的,包括:基本数据类型,Map,POJO和JavaBean。
注意:Mapper 接口不需要实现任何接口或继承任何类。只要方法签名可以被使用来独一无二的识别相应的映射语句。
注意:映射接口可以实现其他的接口。当使用XML绑定映射接口时,你需要确定在恰当的命名空间下有语句。而且,仅有的限制是你不可以在通一层集中的两个接口中有相同的方法签名。
你可以传递多个参数到一个映射方法。如果你这样做了,默认在它们参数列表位置按照字面的param来进行命名。比如:#{param1}, #{param2}等等。如果你希望改变参数的名字,你可以在参数上使用注解 @Param(“参数名字”) 。
你可以传递一个RowBounds 的实例到一个方法中来限制查询的结果。
映射注解
从一开始,MyBatis 已经是一个XML驱动的框架。配置基于XML,而且映射语句也是被定义在XML中。随着MyBatis 3的到来,这里出现了一些可选择的新特性。MyBatis 3是建立于一个综合且强有力的JAVA配置API上。这种配置API是基于MyBatis配置XML的基础的,和新注解基于配置一个道理。在不用介绍大量上面的知识时,注解就可以提供了一个简单的方式来实现简单映射语句。
注意:不幸的是,JAVA注解在表达和灵活方面是有限制的。尽管大量的时间被用来测试,设计和实验,没有得到荒谬的是,最好的MyBatis 映射简化不可以用注解来建立。例如:C#的属性并没有这些限制。因此,MyBatis和.NET会从XML中会有更加丰富的选择。也就是说,JAVA基于注解的配置也不是没有好处的。
注解正如下面的这些:
Mapper 注解的例子:
这个例子展示了使用@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);

这个例子展示了使用@SelectKey注解在插入之后取回一个同一的值:

@Insert("insert into table2 (name) values(#{name})")@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)int insertTable2(Name name);

这个例子展示了使用@Flush注解来调用SqlSession的flushStatements()方法:

@FlushList<BatchResult> flush();

这些例子展示如何通过@Results注解的具体的id属性命名一个ResultMap

@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);

这个例子展示单独参数使用了注解SelectProvider :

@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();  }}

这个例子展示了多个参数使用注解 Sql Provider :

@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
原创粉丝点击