使用mybatis使用教程 需要重写哪些类

Mybatis封装分页查询的java公用类
Mybatis封装分页查询的java公用类
Mybatis封装分页查询的java公用类
& 分页----对于数据量很大的查询中,是必不可少的。mybatis底层的分页sql语句由于需要我们自己去手动写。而实现分页显示的时候我们需要根据分页查询条件查询符合条件的总记录数和记录的详细情况。因此,若是不去实现封装一下的话,我们需要写两条SQL语句去实现它。一次用于查询记录数目。一次用于查询分页显示的详细记录。当项目中碰到很多需要分页的时候,我们便对于每一个Mapper.xml文件都需要去写两条SQL语句。极其麻烦,代码重用----必须重用。所以,一个公共方法的分页需求应运而生。
& 直接上分页公共代码,其实现的原理是使用了拦截器的拦截作用。拦截一类分页查询的请求。我们根据传进来的参数是否是需要interceptor()方法中拦截的参数,是的话则拦截,并执行相应的SQL追加,否则,不进行追加。直接放行。视作普通查询。
&& 需要在Mybatis的配置文件中配置加载服务器的时候加载该公共类:mybatis-config.xml
&&& &?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&&/properties&
&& &&&&&&&&&&& &plugins&
&&&&&&&&&&&&&&&&&&&&&& &plugin interceptor=&com.iboxpay.clear.filter.PaginationInterceptor&&&/plugin&
&& & & & & && &/plugins&
&&&&& &/configuration&
import java.sql.C
import java.sql.PreparedS
import java.sql.ResultS
import java.sql.SQLE
import java.util.P&& &
import org.apache.ibatis.executor.parameter.ParameterH
import org.apache.ibatis.executor.statement.StatementH&& &
import org.apache.ibatis.mapping.BoundS&& &
import org.apache.ibatis.mapping.MappedS
import org.apache.ibatis.plugin.I&& &
import org.apache.ibatis.plugin.I&& &
import org.apache.ibatis.plugin.I&& &
import org.apache.ibatis.plugin.P&& &
import org.apache.ibatis.plugin.S&& &
import org.apache.ibatis.reflection.MetaO&& &
import org.apache.ibatis.reflection.factory.DefaultObjectF
import org.apache.ibatis.reflection.factory.ObjectF
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperF
import org.apache.ibatis.reflection.wrapper.ObjectWrapperF
import org.apache.ibatis.scripting.defaults.DefaultParameterH
import org.apache.ibatis.session.RowB
import org.slf4j.L
import org.slf4j.LoggerF
&* 分页拦截器
&* @since 10.20.2014
@Intercepts({@Signature(type=StatementHandler.class,method=&prepare&,args={Connection.class})})&& &
public class PaginationInterceptor implements Interceptor {
&& &private final Logger logger = LoggerFactory.getLogger(PaginationInterceptor.class);
&& &private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
&& &private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
&& &public Object intercept(Invocation invocation) throws Throwable { &
&& &&&&& StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); &
&& &&&&& MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, &
&& &&&&& DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); &
&& &&&&& // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 &
&& &&&&& // 可以分离出最原始的的目标类) &
&& &&&&& while (metaStatementHandler.hasGetter(&h&)) { &
&& &&&&&&&&& Object object = metaStatementHandler.getValue(&h&); &
&& &&&&&&&&& metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,& &
&& &&&&&&&&& DEFAULT_OBJECT_WRAPPER_FACTORY); &
&& &&&&& }
&& &&&&& // 分离最后一个代理对象的目标类 &
&& &&&&& while (metaStatementHandler.hasGetter(&target&)) { &
&& &&&&&&&&& Object object = metaStatementHandler.getValue(&target&); &
&& &&&&&&&&& metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,& &
&& &&&&&&&&& DEFAULT_OBJECT_WRAPPER_FACTORY); &
&& &&&&& }
&& &&&&& MappedStatement mappedStatement = (MappedStatement)& &
&& &&&&& metaStatementHandler.getValue(&delegate.mappedStatement&); &
&& &&&&& // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的 &
&& &&&&& //& MappedStatement的sql &
&& &&&&& BoundSql boundSql = (BoundSql) metaStatementHandler.getValue(&delegate.boundSql&); &
&& &&&&& Object parameterObject = boundSql.getParameterObject(); &
&& &&&&& if(parameterObject instanceof& PageParam){
&& &&&&&&&&& if (parameterObject == null) {
&& &&&&&&&&&&&&& throw new NullPointerException(&parameterObject is null!&); &
&& &&&&&&&&& } else {
&& &&&&&&&&&&&&& PageParam page = (PageParam)parameterO &
&& &&&&&&&&&&&&& String sql = boundSql.getSql(); &
&& &&&&&&&&&&&&& // 重写sql &
&& &&&&&&&&&&&&& String pageSql = buildPageSql(sql, page); &
&& &&&&&&&&&&&&& metaStatementHandler.setValue(&delegate.boundSql.sql&, pageSql); &
&& &&&&&&&&&&&&& metaStatementHandler.setValue(&delegate.rowBounds.offset&,& &
&& &&&&&&&&&&&&& RowBounds.NO_ROW_OFFSET); &
&& &&&&&&&&&&&&& metaStatementHandler.setValue(&delegate.rowBounds.limit&, RowBounds.NO_ROW_LIMIT); &
&& &&&&&&&&&&&&& Connection connection = (Connection) invocation.getArgs()[0]; &
&& &&&&&&&&&&&&& // 重设分页参数里的总页数等 &
&& &&&&&&&&&&&&& setPageParameter(sql, connection, mappedStatement, boundSql, page); &
&& &&&&&&&&& }
&& &&&&& } &
&& &&&&& // 将执行权交给下一个拦截器 &
&& &&&&& return invocation.proceed(); &
&& &private String buildPageSql(String sql, PageParam page) { &
&& &&&& if (page != null) { &
&& &&&&&&&& StringBuilder pageSql = new StringBuilder(); &
&& &&&&&&&&&&&& pageSql = buildPageSqlForOracle(sql, page); &
&& &&&&&&&& return pageSql.toString(); &
&& &&&& } else {
&& &&&&&&&& &
&& &&&& } &
&& &public StringBuilder buildPageSqlForOracle(String sql, PageParam page) {
&& &&&& StringBuilder pageSql = new StringBuilder(100);
&& &&&& String beginrow = String.valueOf((page.getCurrentPage() - 1) * page.getPageSize()); &
&& &&&& String endrow = String.valueOf(page.getCurrentPage() * page.getPageSize()); &
&& &&&& pageSql.append(&select * from ( select temp.*, rownum row_id from ( &); &
&& &&&& pageSql.append(sql); &
&& &&&& pageSql.append(& ) temp where rownum &= &).append(endrow);
&& &&&& pageSql.append(&) where row_id & &).append(beginrow);
&& &&&& return pageS &
&& & * 从数据库里查询总的记录数并计算总页数,回写进分页参数&code&PageParam&/code&,这样调用 &
&& & * 者就可用通过 分页参数&code&PageParam&/code&获得相关信息。
&& & * @param sql
&& & * @param connection
&& & * @param mappedStatement
&& & * @param boundSql
&& & * @param page
&& & * @throws SQLException
&& &private void setPageParameter(String sql, Connection connection, MappedStatement mappedStatement, &
&& &&&&&&&& BoundSql boundSql, PageParam page) throws SQLException { &
&& &&&& // 记录总记录数 &
&& &&&& String countSql = &select count(0) from (& + sql + &)&; &
&& &&&& PreparedStatement countStmt = &
&& &&&& ResultSet rs = &
&& &&&& try { &
&& &&&&&&&& countStmt = connection.prepareStatement(countSql); &
&& &&&&&&&& BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, &
&& &&&&&&&&&&&&&&&& boundSql.getParameterMappings(), boundSql.getParameterObject()); &
&& &&&&&&&& setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject()); &
&& &&&&&&&& rs = countStmt.executeQuery();
&& &&&&&&&& int totalCount = 0; &
&& &&&&&&&& if (rs.next()) {
&& &&&&&&&&&&&& totalCount = rs.getInt(1); &
&& &&&&&&&& }
&& &&&&&&&& page.setTotalCount(totalCount); &
&& &&&&&&&& int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1); &
&& &&&&&&&& page.setTotalPage(totalPage);
&& &&&& } catch (SQLException e) { &
&& &&&&&&&& logger.error(&exception&, e);
&& &&&& } finally {
&& &&&&&&&& try { &
&& &&&&&&&&&&&& rs.close(); &
&& &&&&&&&& } catch (SQLException e) { &
&& &&&&&&&&&&&& logger.error(&exception&, e); &
&& &&&&&&&& } &
&& &&&&&&&& try { &
&& &&&&&&&&&&&& countStmt.close(); &
&& &&&&&&&& } catch (SQLException e) { &
&& &&&&&&&&&&&& logger.error(&exception&, e); &
&& &&&&&&&& } &
&& &&&& } &
&& &private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, &
&& &&&&&&&& Object parameterObject) throws SQLException { &
&& &&&& ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql); &
&& &&&& parameterHandler.setParameters(ps); &
&&& @Override
&&& public Object plugin(Object target) {&& &
&&&&&&& if (target instanceof StatementHandler) { &
&&&&&&&&&&& return Plugin.wrap(target, this);
&&&&&&& } else {
&&&&&&&&&&&
&&& @Override
&&& public void setProperties(Properties arg0) {&& &
将日志的过滤模式调到DEBUG模式,控制台可以打印出SQL
使用上述方法处理的分页查询,其只需要一条SQL语句就可以(Mapper.xml文件的SQL)
&select id=&selectChannelSettleByParam& parameterType=&PageParam& resultMap=&RS_CHANNELSETTLE&&
&& &&& &&![CDATA[
&& &&& &&& &select& *
&& &&& &]]&
&& &&& &&& &from channlsettle where 1=1
&& &&& &&& &&if test=&params.channelSettleModel.channelId != null and 1000 != params.channelSettleModel.channelId&&AND CHANNL_ID=#{params.channelSettleModel.channelId}&/if&
&& &&& &&& &&if test=&params.channelSettleModel.clearStartTime != null and '' != params.channelSettleModel.clearStartTime&&
&& &&& &&& &&& &&![CDATA[ &
&&&&& &&& &&& &&& &&& &AND to_number(CLEAR_DATE) &= to_number(substr(#{params.channelSettleModel.clearStartTime},0,8))& &
&&& &&& &&& &&& &]]&
&& &&& &&& &&/if&
&& &&& &&& &&if test=&params.channelSettleModel.clearEndTime != null and '' != params.channelSettleModel.clearEndTime&&
&& &&& &&& &&& &&![CDATA[ &
&&&&& &&& &&& &&& &&& &AND to_number(CLEAR_DATE) &= to_number(substr(#{params.channelSettleModel.clearEndTime},0,8))& &
&&& &&& &&& &&& &]]&
&& &&& &&& &&/if&
&& &&& &&& &order by INSTDATE desc
&& &&/select&
控制台打印的SQL:
第一条:select count(0) from (select *& from channlsettle where 1=1 AND CHANNL_ID=? AND to_number(CLEAR_DATE) &= to_number(substr(?,0,8)) AND to_number(CLEAR_DATE) &= to_number(substr(?,0,8)) order by INSTDATE desc)
第二条:select * from ( select temp.*, rownum row_id from ( select *& from channlsettle where 1=1 AND CHANNL_ID=? AND to_number(CLEAR_DATE) &= to_number(substr(?,0,8)) AND to_number(CLEAR_DATE) &= to_number(substr(?,0,8)) order
by INSTDATE desc ) temp where rownum &= 20) where row_id & 0
从而让公共类实现了我们需要在Mapper.xml配置文件中重复写入两条SQL的工作,以后没一个分页查询都可以使用。
感谢关注 Ithao123ExtJS频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊Mybatis教程及使用配置
一.Mybatis简介
MyBatis由Clinton Begin 在2002 年创建,其后,捐献给了Apache基金会,成立了iBatis 项目。2010 年5 月,将代码库迁至Google Code,并更名为MyBatis。
MyBatis 是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型、Map 接口和POJO 到数据库记录。相对Hibernate和Apache OJB等“一站式”ORM解决方案而言,Mybatis 是一种“半自动化”的ORM实现。
二.从JDBC到Mybatis
1. &JDBC查询数据库数据,一般需要以下七个步骤:
(1)&&加载JDBC驱动
(2)&&建立并获取数据库连接
(3)&&创建&JDBC Statements&对象
(4)&&设置SQL语句的传入参数
(5)&&执行SQL语句并获得查询结果
(6)&&对查询结果进行转换处理并将处理结果返回
(7)&&释放相关资源(关闭Connection,关闭Statement,关闭ResultSet)
实现JDBC有七个步骤,哪些步骤是可以进一步封装的,减少我们开发的代码量?
2. &JDBC演变到Mybatis过程
第一步优化:连接获取和释放
问题描述:通过JDBC的方式数据库连接频繁的开启和关闭本身就造成了资源的浪费,影响系统的性能;但是现在连接池多种多样,可能存在变化,有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池。
解决问题:数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题,通过连接池就可以反复利用已经建立的连接去访问数据库了,减少连接的开启和关闭的时间。
同时通过DataSource进行隔离解耦,统一从DataSource里面获取数据库连接,DataSource具体由DBCP实现还是由容器的JNDI实现都可以,将DataSource的具体实现通过让用户配置来应对变化。
第二步优化:SQL统一存取
问题描述:通过JDBC的方式,可读性很差,不利于维护以及做性能调优;改动Java代码需要重新编译、打包部署。不利于取出SQL在数据库客户端执行(取出后还得删掉中间的Java代码,编写好的SQL语句写好后还得通过+号在Java进行拼凑)。
&&&& 解决问题:把SQL语句统一集中放到配置文件,通过SQL语句的key值去获取对应的SQL语句。
第三步优化:传入参数映射和动态SQL
问题描述:很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配。但是,如果我们传入的参数是不确定的(比如列表查询,根据用户填写的查询条件不同,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句的命运。
解决问题:通过专门的SQL解析器来解析SQL语句,SQL语句经过解析后就可以动态的生成符合上下文的SQL语句,同时使用#变量名#表示占位符变量,使用$变量名$表示非占位符变量
第四步优化:结果映射和结果缓存
问题描述:执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源是一整套下来的。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以搞定了
解决问题:一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等等,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值copy到对应的数据结构上。
&&&&& 接下来,我们可以进而考虑对SQL执行结果的缓存来提升性能。缓存数据都是key-value的格式,那么这个key怎么来呢?怎么保证唯一呢?即使同一条SQL语句几次访问的过程中由于传入参数的不同,得到的执行SQL语句也是不同的。那么缓存起来的时候是多对。但是SQL语句和传入参数两部分合起来可以作为数据缓存的key值。
第五步优化:解决重复SQL语句问题
问题描述:将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。
解决问题:通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。
&3. &优化的总结
对JDBC的优化和封装:
(1)&使用数据库连接池对连接进行管理
(2)&SQL语句统一存放到配置文件
(3)&SQL语句变量和传入参数的映射以及动态SQL
(4)&动态SQL语句的处理
(5)&对数据库操作结果的映射和结果缓存
(6)&SQL语句的重复使用
三.框架整体设计
1.&&&&&& 总体流程
(1)加载配置并初始化
触发条件:加载配置文件
& & && &&&配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)接收调用请求
触发条件:调用Mybatis提供的API
& & & 传入参数:为SQL的ID和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。
(3)处理操作请求
&触发条件:API接口层传递请求过来
&&&&&&&&&&&&&&&&&& &&&传入参数:为SQL的ID和传入参数对象
&&&&&&&&&&&&&&&&&& &&&处理过程:
& & & (A)根据SQL的ID查找对应的MappedStatement对象。
& & & (B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
& & &&(C)获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
& & & (D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
& & & (E)释放连接资源。
&(4)返回结果处理
& &将最终的处理结果返回
2.&&&&&& 功能架构设计
把Mybatis的功能架构分为三层:
(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
(3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
3.&&&&&& 框架架构设计
框架架构讲解:
(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
(3)&SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
四.Mybatis入门
每一个Mybatis应该都是以一个SqlSessionFactory实例为中心的,一个SqlSessionFactory实例都可以使用SqlSessionFactoryBuilder来创造。从配置类中创造的定制SqlSessionFactoryBuilder 实例,可以使用XML配置文件来生成一个SqlSessionFactory 实例。
1.&&&&&& 从xml中创造SqlSessionFactory
MyBatis 有一个Resources 通用类,类中有许多方法可以简单地从类路径和其他地址中加载资源。
String resource = "org/mybatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);
XML 文件包含了许多MyBatis 的核心设置,包括一个获取数据库连接(Connection)实例的数据源(DataSource),一个决定事务作用域和操作的TransactionManager。全部的XML 配置文件的内容将在以后提到,先给出一个简单的样子。
&?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&
&environments default="development"&
&environment id="development"&
&transactionManager type="JDBC"/&
&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&
&mapper resource="org/mybatis/example/XXMapper.xml"/&
&/mappers&
&/configuration&
2.&&&&&& 不使用xml文件新建SqlSessionFactory
DataSource dataSource = DataSourceFactory.getDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment =
new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(XXMapper.class);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(configuration);
3.&&&&&& 使用SqlSessionFactory获取SqlSession
通过一个SqlSessionFactory,就可以获取一个SqlSession实例,SqlSession包含了针对数据库执行语句的每一个方法,直接使用SqlSession执行已经映射的每一个SQL语句:
SqlSession session = sqlSessionFactory.openSession();
XXMapper mapper = session.getMapper(XXMapper.class);
XX &xx= mapper.selectXx (101);
} finally {
session.close();
五.探究SQL映射语句
接下来先看一个简单的demo,来完成SqlSession的调用过程
&?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="com.coin.dao.PersonDao"&
&&& &&&& &select id="getPerson" resultType="Person" parameterType="long"&
&&&&&&&&&&& SELECT id,name
&&&&&&&&&&& FROM T_Person
&&&&&&&&&&& WHERE id = #{id}
&/select&&/mapper&
可以用下列语句简单地针对Mapper 接口进行调用上面文件,代码如下:
PersonDao mapper = session.getMapper(PersonDao.class);
Person p= mapper.getPerson (1);
还有一个关于Mapper 类的技巧。它们的映射语句完全不需要使用XML 来配置,可以使用JAVA 注解方式来取代。比如,上面的XML 语句可以替换为:
public interface PersonDao {
@Select("SELECT id,name
&&&&&&&&&&& FROM T_Person
&&&&&&&&&&& WHERE id = #{id}
Person& getPerson (int id);
总结:注解是非常简单明了的,但是JAVA 注解既有局限性,在语句比较复杂的情况下又比较容易混乱。所以,如果你的语句比较复杂,最好还是使用XML 来映射语句。
六.作用域和生命周期
1.&&&&&& SqlSessionFactoryBuilder
这个类可以被初始,使用和丢弃,因为如果已经创建好一个SqlSessionFactory后就不用再保留它,所以SqlSessionFactoryBuilder的最好作用域是方法体内的。
2.&&&&&& SqlSessionFactory
一旦创建,SqlSessionFactory 就会在整个应用过程中始终存在。所以没有理由去销毁和再创建它,一个应用运行中也不建议多次创建SqlSessionFactory。因此SqlSessionFactory最好的作用域是Application。可以结合使用Google Guice 或Spring 来进行依赖反射。这些框架允许你生成管理器来管理SqlSessionFactory 的单例生命周期。
3.&&&&&& SqlSession
每个线程都有自己的SqlSession 实例,SqlSession 实例是不能被共享,也是不是线程安全的。因此最好使用Request 作用域或者方法体作用域。比如说在Servlet 中的HttpSession 中。如果你正在使用WEB 框架,应该让SqlSession 跟随HTTP 请求的相似作用域。也就是说,在收到一个HTTP 请求过后,打开SqlSession,等返回一个回应以后,立马关掉这个SqlSession。关闭SqlSession 是非常重要的。你必须要确保SqlSession 在finally 方法体中正常关闭。可以使用下面的标准方式来关闭:
SqlSession session = sqlSessionFactory.openSession();
// do work
} finally {
session.close();
使用这种模式来贯穿你的所有代码,以确保所有数据库资源都被完全关闭。[这是假定不是使用你自己的数据库连接,而是使用MyBatis 来管理你的数据库连接资源]。
4.&&&&&& Mapper实例
Mapper是一种创建用于绑定映射语句的接口。Mapper接口的实例是用SqlSession来获得的,所以Mapper 实例作用域像SqlSession 一样,使用请求作用域。在方法被调用的时候调用Mapper实例,然后使用后,就会自动销毁掉,而不需要使用明确的注销。下面例子演示如何操作:
SqlSession session = sqlSessionFactory.openSession();
PersonDao mapper = session.getMapper(PersonDao.class);
// do work
} finally {
session.close();
七.Mapper的XML配置文件
Mapper的XML配置文件包含一些设置和属性,用于增强Mybatis的动作。Configuration的各个节点配置如下:
1.&&&&&& 属性(properties)
JAVA 属性文件就可以配置直观的、可代替的属性,或者是属性项的子项。比如:
&properties resource="org/mybatis/example/config.properties"&
&property name="username" value="test"/&
&property name="password" value="test/&
&/properties&
通过动态配置,这些属性都可以用替换整个文件的值。例如:
&dataSource type="POOLED"&
&property name="driver" value="${driver}"/&
&property name="url" value="${url}"/&
&property name="username" value="${username}"/&
&property name="password" value="${password}"/&
&/dataSource&
例子中的usrname 和password 将被属性文件中设置的值所替换, driver 和value 属性也将被config.properties 文件中值所替换,这为配置提供了多种选择。
属性值也可以设入到SqlSessionBuilder.build()方法中,例如:
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, environment, props);
如果一个属性项在多个地方出现,那MyBatis 将按以下顺序加载:
􀁺 属性文件中的属性项首先被读取
􀁺 在类路径或URL 资源中读取的属性项第二顺序加载,并且可以覆盖第一顺序加载的值
􀁺 在方法体中给定的参数值最后加载,覆盖上述两种加载的值。
2.&&&&&& 设置(settings)
这是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="15000"/&
&/settings&
3.&&&&&& 类型别名(typeAliases)
类型别名是Java 类型的简称。它仅仅只是关联到XML 配置,简写冗长的JAVA 类名。例如:
&typeAliases&
&typeAlias alias="Person" &&type="com.coin.model.Person "/&
&/typeAliases&
&typeAliases&
使用这个配置,“Person”就能在任何地方代替“com.coin.model.Person”被使用。
对于普通的Java类型,有许多内建的类型别名。它们都是大小写不敏感的,由于重载的名字,要注意原生类型的特殊处理
别名映射的类型_bytebyte_longlong_shortshort_intint_integerint_doubledouble_floatfloat_booleanbooleanstringStringbyteBytelongLongshortShortintIntegerintegerIntegerdoubleDoublefloatFloatbooleanBooleandateDatedecimalBigDecimalbigdecimalBigDecimalobjectObjectmapMaphashmapHashMaplistListarraylistArrayListcollectionCollectioniteratorIterator
4.&&&&&& 类型句柄(typeHandlers)
无论是MyBatis在预处理语句中设置一个参数,还是从结果集中取出一个值时,类型处理器被用来将获取的值以合适的方式转换成Java类型。下面这个表格描述了默认的类型处理器。
类型处理器Java类型JDBC类型BooleanTypeHandlerBoolean,boolean任何兼容的布尔值ByteTypeHandlerByte,byte任何兼容的数字或字节类型ShortTypeHandlerShort,short任何兼容的数字或短整型IntegerTypeHandlerInteger,int任何兼容的数字和整型LongTypeHandlerLong,long任何兼容的数字或长整型FloatTypeHandlerFloat,float任何兼容的数字或单精度浮点型DoubleTypeHandlerDouble,double任何兼容的数字或双精度浮点型BigDecimalTypeHandlerBigDecimal任何兼容的数字或十进制小数类型StringTypeHandlerStringCHAR和VARCHAR类型ClobTypeHandlerStringCLOB和LONGVARCHAR类型NStringTypeHandlerStringNVARCHAR和NCHAR类型NClobTypeHandlerStringNCLOB类型ByteArrayTypeHandlerbyte[]任何兼容的字节流类型BlobTypeHandlerbyte[]BLOB和LONGVARBINARY类型DateTypeHandlerDate(java.util)TIMESTAMP类型DateOnlyTypeHandlerDate(java.util)DATE类型TimeOnlyTypeHandlerDate(java.util)TIME类型SqlTimestampTypeHandlerTimestamp(java.sql)TIMESTAMP类型SqlDateTypeHandlerDate(java.sql)DATE类型SqlTimeTypeHandlerTime(java.sql)TIME类型ObjectTypeHandlerAny其他或未指定类型EnumTypeHandlerEnumeration类型VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。
可以重写(loverride)类型句柄或者是创建你自己的方式来处理不支持或者是非标准的类型。只需要简单地实现org.mybatis.type 包里的TypeHandler,并且映射你的新类型句柄类到一个JAVA 类型,再选定一个JDBC 类型。例如:
public class ExampleTypeHandler implements TypeHandler {
public void setParameter(
PreparedStatement ps, int i, Object parameter,JdbcType jdbcType)
throws SQLException {
&&System.out.println("setParameter&-&parameter:&"&+&((String)&parameter)&+&",&jdbcType:&"&+&jdbcType.TYPE_CODE);&&
ps.setString(i, (String) parameter);
} public Object getResult(
ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
} public Object getResult(
CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getString(columnIndex);
// MapperConfig.xml
&typeHandlers&
&typeHandler javaType="String" jdbcType="VARCHAR"
handler="org.mybatis.example.ExampleTypeHandler"/&
&/typeHandlers&
这样的类型句柄,将会覆盖现有的处理JAVA String 属性与VARCHAR 和返回值的类型句柄。注意,MyBatis 无法省查数据库的元数据从而决定类型,所以你必须指定参数它是一个VARCHAR 类型,并且结果映射到正确的类型句柄上。这么做主要是由于MyBatis 在没有执行语句之类,无法得知数据的类型。
5.&&&&&& 对象工厂(ObjectFactory)
每次MyBatis&为结果对象创建一个新实例,都会用到ObjectFactory。默认的ObjectFactory&与使用目标类的构造函数创建一个实例毫无区别,如果有已经映射的参数,那也可能使用带参数的构造函数。
如果你重写ObjectFactory&的默认操作,你可以通过继承org.apache.ibatis.reflection.factory.DefaultObjectFactory创建一下你自己的。
ObjectFactory接口很简单。它包含两个创建用的方法,一个是处理默认构造方法的,另外一个是处理带参数构造方法的。最终,setProperties方法可以被用来配置ObjectFactory。在初始化你的ObjectFactory实例后,objectFactory元素体中定义的属性会被传递给setProperties方法。
public class ExampleObjectFactory extends DefaultObjectFactory {
public Object create(Class type) {
return super.create(type);
&public Object create(
Class type,
List&Class& constructorArgTypes,
List&Object& constructorArgs) {
return super.create(type, constructorArgTypes, constructorArg
public void setProperties(Properties properties) {
super.setProperties(properties);
// MapperConfig.xml
&objectFactory type="org.mybatis.example.ExampleObjectFactory"&
&property name="someProperty" value="100"/&
&/objectFactory&
6.&&&&&& 插件(plugins)
MyBatis允许在某一点拦截已映射语句执行的调用。默认情况下,MyBatis允许使用插件来拦截方法调用:
·&&&&&&&& Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
·&&&&&&&& ParameterHandler(getParameterObject, setParameters)
·&&&&&&&& ResultSetHandler(handleResultSets, handleOutputParameters)
·&&&&&&&& StatementHandler(prepare, parameterize, batch, update, query)
这些类中方法的详情可以通过查看每个方法的签名来发现,而且它们的源代码在MyBatis的发行包中有。应该理解你覆盖方法的行为,假设你所做的要比监视调用要多。如果你尝试修改或覆盖一个给定的方法,你可能会打破MyBatis的核心。这是低层次的类和方法,要谨慎使用插件。
使用插件是它们提供的非常简单的力量。简单实现拦截器接口,要确定你想拦截的指定签名。
@Intercepts({@Signature(
type= Executor.class
method = "update"
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
&public Object plugin(Object target) {
return Plugin.wrap(target, this);
public void setProperties(Properties properties) {
// MapperConfig.xml
&plugin interceptor="org.mybatis.example.ExamplePlugin"&
&property name="someProperty" value="100"/&
&/plugins&
上面的这个插件可以在执行器上拦截所有“update”方法的调用,这里的执行器,是一个映射语句内部对象的深架构的执行器。
7.&&&&&& 环境(environments)
MyBatis&可以配置多个环境。这样可以帮助你SQL&映射对应多种数据库。比如说,你想为开发、测试、发布产品配置不用的环境。或者,你想为多个数据库产品共享相同的模式,或者也想使用相同的SQL映射。虽然你可以配置多重环境,但是也可以只选择一对一SqlSessionFactory实例。
这样想要指定生成哪个环境,只要简单地把它做了一个可选参数代入SqlSessionFactoryBuilder。下面两种方式都可以:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);
如果环境变更省略了,就会载入默认的环境变量。像这样:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);
环境元素定义这些环境是如何被配置的。
&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&
注意这些关键段:
􀁺 设定一个默认环境ID
􀁺 这个环境ID 对每个环境都起作用
􀁺 配置事务管理器(MyBatis 有两个事务管理类型:JDBC,MANAGED)
􀁺 配置数据源(数据源类型有三种:UNPOOLED,POOLED,JNDI)
8.&&&&&& 映射器(Mappers)
这里是告诉MyBatis&去哪寻找映射SQL&的语句。可以使用类路径中的资源引用,或者使用字符,输入确切的URL&引用。
&&& &mappers&
&&&&&&& &mapper &&resource="com/coin /dao/personDao.xml"/&
&& &/mappers&
八.SQL映射语句文件
Mybatis真正强大的地方就是在映射语句,SQL映射XML文件包含一些的元素:
􀁺 cache – 配置给定模式的缓存
􀁺 cache-ref – 从别的模式中引用一个缓存
􀁺 resultMap – 这是最复杂而却强大的一个元素了,它描述如何从结果集中加载对象
􀁺 sql – 一个可以被其他语句复用的SQL 块
􀁺 select – 映射SELECT 语句
􀁺 insert – 映射INSERT 语句
􀁺 update – 映射UPDATE 语句
􀁺 delete – 映射DELEETE 语句
1.&&&&&& Select
一个Select元素很简单,例如:
&&&&&& &&& &select id="getPerson" resultType="Person" parameterType="long"&
&&&&&&&&&&& SELECT ID,Name
&&&&&&&&&&& FROM T_PERSON
&&&&&&&&&&& WHERE id = #{id}
&&&&&&&&&&&
& &/select&
这条语句就叫做‘getAllPersons,有一个long参数,并返回一个Person类型的对象。参数的标识是:#{ id }。
select 语句属性配置细节:
属性描述取值默认id在这个模式下唯一的标识符,可被其它语句引用parameterType传给此语句的参数的完整类名或别名resultType语句返回值类型的整类名或别名。注意,如果是集合,那么这里填写的是集合的项的整类名或别名,而不是集合本身的类名。(resultType 与resultMap 不能并用)resultMap引用的外部resultMap 名。结果集映射是MyBatis 中最强大的特性。许多复杂的映射都可以轻松解决。(resultType 与resultMap 不能并用)flushCache如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为falsetrue|falsefalseuseCache如果设为true,则语句的结果集将被缓存。select 语句默认设为false&true|false&falsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定true|falsefalsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定正整数未设置fetchSize设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定正整数驱动器决定statementTypestatement,preparedstatement,callablestatement。预准备语句、可调用语句STATEMENTPREPAREDCALLABLEPREPAREDresultSetTypeforward_only,scroll_sensitive,scroll_insensitive只转发,滚动敏感,不区分大小写的滚动FORWARD_ONLYSCROLL_SENSITIVESCROLL_INSENSITIVE驱动器决定
2.&&&&&& insert
insert可以使用数据库支持的自动生成主键策略,设置useGeneratedKeys=”true”,然后把keyProperty 设成对应的列,就搞定了。&还可以使用selectKey元素。下面例子,使用mysql数据库nextval(\\'student\\')为自定义函数,用来生成一个key。
下面一个例子是在oracle数据库里面的:
&insert id="createPerson" parameterType="Person"&
&&& INSERT INTO …VALUES (#{id},#{name}
insert语句属性配置细节:
属性描述取值默认id在这个模式下唯一的标识符,可被其它语句引用parameterType传给此语句的参数的完整类名或别名flushCache如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为falsetrue|falsefalseuseCache如果设为true,则语句的结果集将被缓存。select 语句默认设为false&true|false&falsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定true|falsefalsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定正整数未设置fetchSize设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定正整数驱动器决定statementTypestatement,preparedstatement,callablestatement。预准备语句、可调用语句STATEMENTPREPAREDCALLABLEPREPAREDuseGeneratedKeys告诉MyBatis 使用JDBC 的getGeneratedKeys 方法来获取数据库自己生成的主键(MySQL、SQLSERVER 等关系型数据库会有自动生成的字段)。默认:falsetrue|falsefalsekeyProperty标识一个将要被MyBatis 设置进getGeneratedKeys 的key 所返回的值,或者为insert 语句使用一个selectKey子元素。
selectKey语句属性配置细节:
属性描述取值keyPropertyselectKey 语句生成结果需要设置的属性。resultType生成结果类型,MyBatis 允许使用基本的数据类型,包括String 、int类型。order可以设成BEFORE 或者AFTER,如果设为BEFORE,那它会先选择主键,然后设置keyProperty,再执行insert语句;如果设为AFTER,它就先运行insert 语句再运行selectKey 语句,通常是insert 语句中内部调用数据库(像Oracle)内嵌的序列机制。&BEFOREAFTERstatementType像上面的那样, MyBatis 支持STATEMENT,PREPARED和CALLABLE 的语句形式, 对应Statement ,PreparedStatement 和CallableStatement 响应STATEMENTPREPAREDCALLABLE
3.&&&&&& update,delete
update,delete的例子如下:
&&& &update id="updatePerson" parameterType="Person"&
&&&&&&&&&&& UPDATE T_PERSON
&&&&&&&&&&& SET NAME = #{name},&&&&
&&&&&&&&&&& WHERE ID = #{id}
&&& &/update&
&&& &delete id="deletePerson" parameterType="long"&
&&&&&&&&&&& DELETE T_PERSON
&&&&&&&&&&& WHERE ID = #{value}
update、delete语句属性配置细节:
属性描述取值默认id在这个模式下唯一的标识符,可被其它语句引用parameterType传给此语句的参数的完整类名或别名flushCache如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为falsetrue|falsefalseuseCache如果设为true,则语句的结果集将被缓存。select 语句默认设为false&true|false&falsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定true|falsefalsetimeout&设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定正整数未设置fetchSize设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定正整数驱动器决定statementTypestatement,preparedstatement,callablestatement。预准备语句、可调用语句STATEMENTPREPAREDCALLABLEPREPARED
4.&&&&&& SQL
Sql元素用来定义一个可以复用的SQL 语句段,供其它语句调用。比如:
&sql id="columns"&ID id,NAME name&/sql&
这个语句块,可以包含到别的语句中,比如:
&select id="getAllPersons" resultType="Person"&
&&&&&&& SELECT &include refid="columns"/&
&&&&&&&&&&& FROM T_PERSON
&&& &/select&
5.&&&&&& 参数(parameters)
&MyBatis的参数可以使用的基本数据类型和Java的复杂数据类型。&&&&& & 基本数据类型,String,int,date等。&&&&&&& 但是使用基本数据类型,只能提供一个参数,所以需要使用Java实体类,或Map类型做参数类型。通过#{}可以直接得到其属性。
5.1& 基本类型参数
&select id="getPerson" resultType="Person" parameterType="long"&
&&&&&&&&&&& SELECT ID id,NAME name
&&&&&&&&&&& FROM T_PERSON
&&&&&&&&&&& WHERE ID = #{id}
&&& & &/select&
5.2& Java实体类型参数
&&& &&&&& &insert id="createPerson" parameterType="Person"&
&&&&&&&&&&&&&&&&&&& INSERT INTO T_PERSON(ID,NAME)
&&&&&&&&&&& VALUES (#{id},#{name}
多参数的实现
如果想传入多个参数,则需要在接口的参数上添加@Param注解。给出一个实例:
&!-- 查询学生list,like姓名、=性别,多参数方式 --&
&&& &select id="getStudentListWhereParam" resultMap="studentResultMap"&
&&&&&&& SELECT * from student ST
&&&&&&& &where&
&&&&&&&&&&& &if test="name!=null and name!=\\'\\' "&
&&&&&&&&&&&&&&& ST.name LIKE CONCAT(CONCAT(\\'%\\', #{name}),\\'%\\')
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="gender!= null and gender!= \\'\\' "&
&&&&&&&&&&&&&&& AND ST.gender = #{gender}
&&&&&&&&&&& &/if&
&&&&&&& &/where&
&&& &/select&
5.3& 字符串代入法
默认的情况下,使用#{}语法会促使MyBatis 生成PreparedStatement 属性并且使用PreparedStatement 的参数(=?)来安全的设置值。尽量这些是快捷安全,也是经常使用的。但有时候你可能想直接未更改的字符串代入到SQL 语句中。比如说,对于ORDER BY,你可能会这样使用:ORDER BY ${columnName}但MyBatis 不会修改和规避掉这个字符串。&&&&&&& 注意:这样地接收和应用一个用户输入到未更改的语句中,是非常不安全的。这会让用户能植入破坏代码,所以,要么要求字段不要允许客户输入,要么你直接来检测他的合法性&。
6.&&&&&& resultMap
6.1& 一对一
&resultMap id="studentTeacherResultMap" type="student"&
&&&&&&&&&& &id property="id" column="id"/&
&&&&&&&&& &result property="name" column="name"/&
&&&&&&&&& &result property="gender" column="gender"/&
&&&&&&&&& &result property="major" column="major"/&&&
&&&&&&&&& &result property="grade" column="grade"/&
&&&&&&&&&&&
&&&&&&&&& &!--使用resultMap属性引用下面的教师实体映射--&
&&&&&&&&& &association property="supervisor" javaType="teacher"
&&&&&&&&& resultMap="com.coin.dao.teacher.TeacherDao.supervisorResultMap"/&
&&&&& &/resultMap&
&&&&&& &select id="getById" parameterType="int" resultMap="studentTeacherResultMap"&
&&&&&&&&& select st.id,st.name,st.gender,&
&&&&&&&&& st.major,st.grade,&
&&&&&&&&& &!--为教师的id取别名,避免MyBatis向教师实体注入&
&&&&&&&&& 此属性时与学生id混淆。以下的name和gender等属性&
&&&&&&&&& 也是如此--&
&&&&&&&&& t.id t_id,t.name t_name,t.gender t_gender,&
&&&&&&&&& t.title,t.research_area&
&&&&&&&&& from student st, teacher t&
&&&&&&&&& where st.supervisor_id = t.id&
&&&&&&&&& and st.id=#{id}&
&& &/select&
6.2&&& 一对多
&&&& &!--TeacherMapper接口中getById方法对应的SQL语句。&
&&&&&&&& 查询教师及其指导的学生的信息。由于教师、学生都有&
&&&&&&&& id、name、gender等属性,因此给教师的字段都起了别名--&
&&&&&&&& &select id="getById" parameterType="int"& resultMap="supervisorResultMap"&
&&&&&&&&& select t.id t_id, t.name t_name, t.gender t_gender,&
&&&&&&&&& t.research_area t_research_area, t.title t_title,&
&&&&&&&&& s.id,s.name, s.gender,s.major,s.grade&
&&&&&&&&& from teacher t,student s where t.id=#{id}&
&&&&&&&&& and s.supervisor_id = t.id&
&&&&&&&& &/select&
&&&&&&&& &!--教师实体映射--&
&&&&&&&& &resultMap id="supervisorResultMap" type="teacher"&
&&&&&&&&&&& &id property="id" column="t_id"/&
&&&&&&&&&&& &result property="name" column="t_name"/&
&&&&&&&&&&& &result property="gender" column="t_gender"/&
&&&&&&&&&&& &result property="researchArea" column="t_research_area"/&&&
&&&&&&&&&&& &result property="title" column="t_title"/&
&&&&&&&&&&& &!--collection元素映射教师的指导学生集合的属性。resultMap&
&&&&&&&&&&& 以命名空间名.resultMap的id的形式,引用studentResultMap。&
&&&&&&&&&&& 需要注意的是,上面的select语句中学生的字段名/别名应与&
&&&&&&&&&&& studentResultMap中的column属性一致--&
&&&&&&&&&&& &collection property="supStudents"&&
&&&&&&&&&&&&& resultMap="com.coin.dao.student.StudentDao.studentTeacherResultMap"/&
&&&&&&&& &/resultMap&
九.cache 缓存
默认的情况,缓存是没有开启,除了会话缓存以外,它可以提高性能,且能解决全局依赖。开启二级缓存,只需要在SQL 映射文件中加入简单的一行:&cache/&
这句简单的语句的作用如下:
1. 所有在映射文件里的select 语句都将被缓存。2.&所有在映射文件里insert,update 和delete 语句会清空缓存。3.&缓存使用“最近很少使用”算法来回收4.&缓存不会被设定的时间所清空。5.&每个缓存可以存储1024 个列表或对象的引用(不管查询出来的结果是什么)。6.&缓存将作为“读/写”缓存,意味着获取的对象不是共享的且对调用者是安全的。不会有其它的调用&者或线程潜在修改。
可以采用第三方缓存框架缓存,例如:OSCache,EHCache,Hazelcast
&cache type="org.mybatis.caches.oscache.OSCache"/&
也可以使用cache-ref 来引用另外一个缓存。
&cache-ref namespace=”com.someone.application.data.SomeMapper”/&
十.动态语句
1.&&&&&& if
动态SQL中最常用的事情就是用条件地包含一个where字句。比如:
&select id="getStudentListWhereParam" resultMap="studentResultMap"&
&&&&&&& SELECT * from student ST
&&&&&&& &where&
&&&&&&&&&&& &if test="name!=null and name!=\\'\\' "&
&&&&&&&&&&&&&&& ST.name LIKE CONCAT(CONCAT(\\'%\\', #{name}),\\'%\\')
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="gender!= null and gender!= \\'\\' "&
&&&&&&&&&&&&&&& AND ST.gender = #{gender}
&&&&&&&&&&& &/if&
&&&&&&& &/where&
&&& &/select&
2.&&&&&& choose,when,otherwise
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。类似于Java 的switch 语句,MyBatis提供了choose 元素。
&&& & &select id="findStudentLike"& resultMap="studentResultMap"&
&&&&&&&&&&& SELECT * FROM student ST
&&&&&&&&&&& &where&
&&&&&&&&&&& && &choose&
&&&&&&&&&&&&&&& &when test="name != null"&
&&&&&&&&&&&&&&& &&& ST.name LIKE CONCAT(CONCAT(\\'%\\', #{name}),\\'%\\')
&&&&&&&&&&&&&&& &/when&
&&&&&&&&&&&&&&& &when test="major != null"&
&&&&&&&&&&&&&&& &&& ST.name LIKE CONCAT(CONCAT(\\'%\\', #{major}),\\'%\\')
&&&&&&&&&&&&&&& &/when&
&&&&&&&&&&&&&&& &otherwise&
&&&&&&&&&&&&&&& && AND ST.grade = \\'2012\\'
&&&&&&&&&&&&&&& &/otherwise&
&&&&&&&&&&& & &/choose&
&&&&&&& &/where&
3.&&&&&& set,trim
set元素被用做动态囊括列名来更新,而忽略其它的。
当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET&关键字,和剔除追加到条件末尾的任何不相关的逗号。使用if+set标签修改后,如果某项为null则不进行更新,而是保持数据库原值。如下示例:
&&&&&& &!--& if/set(判断参数) - 将实体类不为空的属性更新 --&
&&& &update id="updateStudent_if_set" parameterType="student"&
&&&&&&& update student ST
&&&&&&& &set&
&&&&&&&&&&& &if test="name!= null and name != \\'\\'"&
&&&&&&&&&&&&&&& ST.name = #{name},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="gender != null and gender != \\'\\'"&
&&&&&&&&&&&&&&& ST.gender = #{gender},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="major!= null and major != \\'\\'"&
&&&&&&&&&&&&&&& ST.major = #{major},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="grade!= null and grade!= \\'\\'"&
&&&&&&&&&&&&&&& ST.grade = #{grade}
&&&&&&&&&&& &/if&
&&&&&&& &/set&
&&&&&&& WHERE ST.id = #{id}
trim是灵活的去除多余关键字的标签,它可以实现where和set的效果
trim等同where效果的例子:
&select id="getStudentListTrimParam" resultMap="studentResultMap"&
&&&&&&& SELECT * from student ST
&&&&&&& &trim& prefix="WHERE" prefixOverrides="AND|OR"&
&&&&&&&&&&& &if test="name!=null and name!=\\'\\' "&
&&&&&&&&&&&&&&& ST.name LIKE CONCAT(CONCAT(\\'%\\', #{name}),\\'%\\')
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="gender!= null and gender!= \\'\\' "&
&&&&&&&&&&&&&&& AND ST.gender = #{gender}
&&&&&&&&&&& &/if&
&&&&&&& &/trim&
&&& &&/select&
trim等同set效果的例子:
&!-- if/trim(判断参数) - 将实体类不为空的属性更新 --&
&&& &update id="updateStudent_if_trim" parameterType="student"&
&&&&&&& update student ST
&&&&&&& &trim prefix="SET" suffixOverrides=","&
&&&&&&&&&&& &if test="name!= null and name != \\'\\'"&
&&&&&&&&&&&&&&& ST.name = #{name},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="gender != null and gender != \\'\\'"&
&&&&&&&&&&&&&&& ST.gender = #{gender},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="major!= null and major != \\'\\'"&
&&&&&&&&&&&&&&& ST.major = #{major},
&&&&&&&&&&& &/if&
&&&&&&&&&&& &if test="grade!= null and grade!= \\'\\'"&
&&&&&&&&&&&&&&& ST.grade = #{grade}
&&&&&&&&&&& &/if&
&&&&&&& &/trim&
&&&&&&& WHERE ST.id = #{id}
4.&&&&&& foreach
&另外一个对于动态SQL 非常必须的,主是要迭代一个集合,通常是用于IN 条件。
4.1& 传入List
&&&&& &select id="forEachStudentList"& resultMap="studentResultMap"&
&&&&&&& SELECT * FROM student ST&
&&&&&&& WHERE ST.id in
&&&&&&& &foreach collection="list" item="item" index="index" open="("& separator=","& close=")"&&&
&&&&&&&&&&&& #{item}&&&
&&&&&&& &/foreach&
&&& &/select&
&4.2& 传入Array
&select id="forEachStudentArray"& resultMap="studentResultMap"&
&&&&&&& SELECT * FROM student ST
&&&&&&& WHERE ST.id in
&&&&&&& &foreach collection="array" item="item" index="index"& open="("& separator=","& close=")"&&&
&&&&&&&&&&&& #{item}&&&
&&&&&&&& &/foreach&
& &/select&
相关文章推荐
Copyright 2012- ( Coin163 ) All Rights Reserved}

我要回帖

更多关于 mybatis group by使用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信