MyBatis使用总结

 

iBatis 从 3.x 开始更名为 MyBatis。除了 Java 以外,还有可用于.Net 的 Mybatis.Net。

 

 相关依赖包 (maven)

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.7</version>
</dependency>

 

映射相关文件自动生成(mybatis-generator)

iBatis 提供了 Abator 用于生成映射相关文件。Mybatis 可以用 mybatis generator 实现类似功能。

生成配置文件

mybatis 默认使用的路径和文件名 (无需配置):src/main/resources/generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- classPathEntry: 数据库的 JDBC 驱动-->
    <classPathEntry location="target\assist\WEB-INF\lib\mysql-connector-java-5.1.32.jar"/>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 去除自动生成的注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
        </commentGenerator>
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/testdb?autoReconnect=true" userId="xxxx" password="xxxxx"/>
        <!-- 生成 Model 类,targetProject: 自动生成代码的位置 -->
        <javaModelGenerator targetPackage="com.demo.models" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
     <!-- 生成 XML 映射文件 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
     <!-- 生成 Mapper 接口 (DAO) -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.demo.mappers" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
     <!-- 通过 javaTypeResolver 元素控制类型转化,也能继承 JavaTypeResolver 接口实现自己的类型转换器。 -->
     <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/> <!-- 将 JDBC DECIMAL 和 NUMERIC 解析为 Integer,而不是 BigDecimal-->
        </javaTypeResolver>
     <!-- 要生成映射代码的数据表,tableName 为表名;domainObjectName 为对应的 javaBean 类名, enablexxxxx 是与 Example 类相关的配置 -->
        <table tableName="person" domainObjectName="Person"/>
        <table tableName="my_table" domainObjectName="myTable" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
      <!--<columnRenamingRule searchString="^D_" replaceString=""/>
     <property name="useActualColumnNames" value="false"/>
--> </table>     ...... </context> </generatorConfiguration>

 

  • Example 类实现了查询条件的对象化。
  • "_" 分隔的字段名会自动转化为驼峰形式。
  • oracle nvarchar/nvarchar2 类型会转化成 Object 类型。
  • oracle 指定精度的数值型字段默认转为 BigDecimal,不指定精度的数值型默认转为 Long。
  • targetProject 属性可以设置为MAVEN,代码将生成在target/generatored-source目录下。
  • generatorConfiguration 节点下添加 <properties resource="jdbc.properties" />,可以在配置中的 ${...} 表示的占位符。获取文件的方式为:Thread.currentThread().getContextClassLoader().getResource(resource)
  • context 节点下添加<plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin> 生成的 pojo 类 implements Serializable。
  • 通过enableCountByExample, enableUpdateByExample, enableDeleteByExample, enableSelectByExample, selectByExampleQueryId等属性可以控制是否生成和使用 xxxExample 类在查询中替代模型类。

 

从属性文件中加载配置

generatorConfig.properties 文件

# 数据库驱动 jar 路径
driver.class.path=target/assist/WEB-INF/lib/mysql-connector-java-5.1.32.jar

# 数据库连接参数 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=utf-8 jdbc.username=uname
jdbc.password=pwd

# 包路径配置
model.package=com.demo.modules.entity
dao.package
=com.demo.modules.mapper
xml.mapper.package
=com.demo.modules.mapper
target.project
=src/main/java

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <properties url="${mybatis.generator.generatorConfig.properties}"> <!--maven pom 文件 properties 中配置的属性 -->
    <classPathEntry location="${driver.class.path}"/>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"/>
        <!-- 生成 Model 类,targetProject: 自动生成代码的位置 -->
        <javaModelGenerator targetPackage="${model.package}" targetProject="${target.project}">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
    ......
    </context>
</generatorConfiguration>

 

 

构建时自动生成

    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
       <!-- 省缺值为:src/main/resources/generatorConfig.xml
       <configurationFile>src/main/resources/mybatis-generator/generatorConfig.xml</configurationFile>--> <verbose>true</verbose> <overwrite>true</overwrite> </configuration>    <executions> <execution> <id>Generate MyBatis Artifacts</id> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin>

 

通过命令行调用

mvn  mybatis-generator:generate 
mvn  mybatis-generator:generate -Dmybatis.generator.overwrite=true

 

直接执行

使用 mybatis-generator-core-xxxx.jar 包

java -jar mybatis-generator-core-1.3.2.jar -configfile generatorConfig.xml -overwrite

 

自定义类型转换 

http://blog.csdn.net/lele2426/article/details/38794399 

 

 

 

MyBatis 映射相关文件

(1). model 类 xxx.java

生成的 model 类是普通的 java 类,包含与数据库表各个字段对应的属性极其 setter 和 getter 方法。

 

(2). 查询条件类 xxxExample.java

http://openwares.net/database/mybatis_generator_example.html

Example 类用于构造复杂的筛选条件。

Criterion

  Criterion 是最基本,最底层的 Where 条件,用于字段级的筛选。主要有以下这些:

  • field IS NULL
  • field IS NOT
  • field > value
  • field >= value
  • field =value
  • field <> value
  • field <= value
  • field < value
  • field LIKE value
  • field NOT LIKE value
  • field BETWEEN value1 AND value2
  • field IN (item1, item2,...)
  • field NOT IN (item1, item2, ...)

  LIKE 模糊查询的 %,? 字符只能在构造查询条件是手动指定。

  Mybatis Generator 会为每个字段生成如上所示的 Criterion,理论上可以构造任何筛选条件,如果字段较多生成的 Example 类会很大。

Criteria

  Criteria 包含了 Cretiron 的集合,同一个 Criteria 中的各个 Cretiron 之间为逻辑与 (AND) 关系。

oredCriteria

  Example 内有一个成员叫 oredCriteria,是 Criteria 的集合,集合中的各个 Criteria 直接为逻辑或 (OR) 的关系。

用法

http://mybatis.org/generator/generatedobjects/exampleClassUsage.html

TestTableExample example = new TestTableExample();
example.or()
    .andField1EqualTo(5).andField2IsNull();

example.or()
.andField3NotEqualTo(9)
.andField4IsNotNull();

List<Integer> field5Values = new ArrayList<Integer>();
field5Values.add(
8);
field5Values.add(
11);
field5Values.add(
14);
field5Values.add(
22);

example.or()
.andField5In(field5Values);

example.or()
.andField6Between(3, 7);

  • or() 方法会产生一个新的 Criteria 对象, 添加到 oredCriteria 中, 并返回这个 Criteria 对象,从而可以链式表达,为其添加 Criterion。
  • Example 类的 distinct 字段用于指定 DISTINCT 查询。
  • orderByClause 字段用于指定 ORDER BY 条件, 这个条件没有构造方法, 直接通过传递字符串值指定。

产生的 SQL 语句如下:

where (field1 = 5 and field2 is null)
     or (field3 <> 9 and field4 is not null)
     or (field5 in (8, 11, 14, 22))
     or (field6 between 3 and 7)

 

 

(3). xxxMapper.xml 文件

sql 语句映射配置文件。

  • mapper 元素需要有一个唯一的 namespace 属性,必须为对应的 Mapper 接口全名。
  • 每个 sql 语句定义都有一个 id,必须与对应的 Mapper 接口中方法同名,可以指定参数类型和返回类型。
  • 每个 sql 语句可以定义 parameterType 和 resultType 指定参数和返回值类型,也可单独定义 parameterMap(见后面的存储过程部分) 和 resultMap 元素然后在 sql 语句元素中引用。 
<?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.demo.mappers.PersonMapper">
  <resultMap id="BaseResultMap" type="com.demo.models.Person">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    ......
  </resultMap>
  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.demo.models.Person">
    <result column="content" jdbcType="LONGVARCHAR" property="content" />
  </resultMap>
<sql id="Update_By_Example_Where_Clause"> <where> <foreach collection="example.oredCriteria" item="criteria" separator="or"> <if test="criteria.valid"> <trim prefix="(" prefixOverrides="and" suffix=")"> <foreach collection="criteria.criteria" item="criterion"> <choose> <when test="criterion.noValue"> and ${criterion.condition} </when> <when test="criterion.singleValue"> and ${criterion.condition} #{criterion.value} </when> <when test="criterion.betweenValue"> and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} </when> <when test="criterion.listValue"> and ${criterion.condition} <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=","> #{listItem} </foreach> </when> </choose> </foreach> </trim> </if> </foreach> </where> </sql> <sql id="Base_Column_List"> id, name </sql> <sql id="Blob_Column_List"> content </sql>

<select id="selectByExampleWithBLOBs" parameterType="com.demos.models.PersonExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from person
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by $orderByClause$
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from person
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from person
where id = #{id,jdbcType=INTEGER}
</delete>

<insert id="insert" parameterType="com.demo.models.Person">
insert into person(id, name, content)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},#{content,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.demo.models.Person">
insert into t_certstore
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
identityName,
</if>
<if test="content != null">
content,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="name!= null">
#{name,jdbcType=VARCHAR},
</if>
<if test="content != null">
#{content,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<update id="updateByExampleSelective" parameterType="map">
update person
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=INTEGER},
</if>
<if test="record.name!= null">
name = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.content != null">
content = #{record.content,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<select id="countByExample" parameterType="com.demo.models.Person" resultType="java.lang.Integer">
   select count(*) from person
  
<if test="_parameter != null">
    <include refid="Example_Where_Clause" />
   </if>
</select>
......
</mapper>

 

xxxMapper.java(接口)

定义与 Mapper.xml 中 sql 语句对应的方法,方法名就是 sql 语句的 id 属性,参数和返回值也要对应。

public interface PersonMapper {
    int countByExample(PersonExample example);int deleteByPrimaryKey(Integer id);
int insert(Personrecord); int insertSelective(Person record); List<CertStore> selectByExampleWithBLOBs(PersonExample example); CertStore selectByPrimaryKey(Integer id); int updateByExampleSelective(@Param("record") Person record, @Param("example")PersonExample example); ...... }

使用了多个参数的时候,可以用 @Param 注解给参数设置名字以区分不同参数,xml 文件中 sql 语句的参数类型为 map,通过参数名访问参数对象的属性。如 @Param(record), 可用 #{record.id} 访问。还可以指定类型,如 #{record.id,jdbcType=INTEGER}。

如果只有一个参数则不需要指定参数的名字,#{...} 会直接访问这个参数对象的属性,如果没有适合的属性则直接代表当前参数。

  • #{token}   会被预编译,能防止 SQL 注入
  • ${token}    动态执行,不能防止 SQL 注入

 

Mybatis 使用

mybatis 配置文件

<?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="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/testdb?autoReconnect=true" />
                <property name="username" value="xxxx" />
                <property name="password" value="xxxx" />
            </dataSource>
        </environment>
    </environments>
   <settings>......</settings>
    <!-- 全局别名设置,在映射文件中只需写别名,而不必写出整个类路径  --> 
<typeAliases>......</typeAliases>  
<!-- 非注解的 sql 映射文件配置,如果使用 mybatis 注解,该 mapper 无需配置,但是如果 mybatis 注解中包含@resultMap 注解,则 mapper 必须配置,给 resultMap 注解使用 -->   <mappers> <mapper resource="mapper/Person.xml" /> <mapper class="com.demo.mapper.CustomPersonMapper" />      ...... </mappers> </configuration>

可以自行创建额外的 sql 映射 xml 文件或基于注解 Mapper 接口,但是都需要加入到 Mybatis 配置中的 mappers 元素里。 

settings

<!-- 全局映射器启用缓存 -->  
<setting name="cacheEnabled" value="true" />  

<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="true" />

<!-- 设置关联对象加载的形态,此处为按需加载字段 (加载字段由 SQL 指 定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="false" />

<!-- 对于未知的 SQL 查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true" />

<!-- 允许使用列标签代替列名 -->
<setting name="useColumnLabel" value="true" />

<!-- 允许使用自定义的主键值 (比如由程序生成的 UUID 32 位编码作为键值),数据表的 PK 生成策略将被覆盖 -->
<setting name="useGeneratedKeys" value="true" />

<!-- 给予被嵌套的 resultMap 以字段 - 属性的映射支持 -->
<setting name="autoMappingBehavior" value="FULL" />

<!-- 对于批量更新操作缓存 SQL 以提高性能 -->
<setting name="defaultExecutorType" value="BATCH" />

<!-- 数据库超过 25000 秒仍未响应则超时 -->
<setting name="defaultStatementTimeout" value="25000" />
......

typeHandlers 用来自定义映射规则,如你可以自定义将 Character 映射为 varchar,plugins 元素则放了一些拦截器接口,你可以继承他们并做一些切面的事情。更多配置如如 properties,objectFactory 等,可以参考 ibatis-3-config.dtd 文档。

使用 Spring 时,不需要此配置文件,而是使用针对 Spring 的专门的配置文件(配置 bean)。

初始化

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory   sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session=sqlSessionFactory .openSession(true);
/**
         * 映射 sql 的标识字符串,
         * com.demo.mappers.personMapper 是 personMapper.xml 文件中 mapper 标签的 namespace 属性的值,
         * getPerson 是 select 标签的 id 属性值,通过 select 标签的 id 属性值就可以找到要执行的 SQL
 */
String statement = "com.demo.mappers.personMapper.getPerson";//映射 sql 的标识字符串
//执行查询返回一个唯一 user 对象的 sql
Person person = session.selectOne(statement, 1);
System.out.println(person);
PersonMapper personMapper = session.getMapper(PersonMapper.class);
personMapper.insert(new Pserson(......));
......
session.commit();
session.close();

 

 

SqlSessionManager sessionManager=SqlSessionManager.newInstance(inputStream);

Configuration configuration = sessionManager.getConfiguration();
MapperRegistry mapperRegistry = configuration.getMapperRegistry();

if(!sessionManager.isManagedSessionStarted())
sessionManager.startManagedSession(true);

 

 

使用 SqlSession 类进行数据库操作

SqlSession 接口提供了常用的数据库操作方法。所有的 statement 参数为 xml 文件中 namespace 加上 sql 语句 id,如 com.demo.mappers.PersonMapper.selectByPrimaryKey。

  • <T> T selectOne(String statement);
  • <T> T selectOne(String statement, Object parameter);
  • <E> List<E> selectList(String statement);
  • <E> List<E> selectList(String statement, Object parameter);
  • <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
  • <K, V> Map<K, V> selectMap(String statement, String mapKey);
  • <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
  • <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
  • void select(String statement, Object parameter, ResultHandler handler);
  • void select(String statement, ResultHandler handler);
  • void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
  • int insert(String statement);
  • int insert(String statement, Object parameter);
  • int update(String statement);
  • int update(String statement, Object parameter);
  • int delete(String statement);
  • int delete(String statement, Object parameter);

以上这些方法只需要用到 XML 映射文件,不需要 Mapper 接口。

 

其他操作

  • void commit();
  • void commit(boolean force);
  • void rollback();
  • void rollback(boolean force);
  • List<BatchResult> flushStatements();
  • void close();
  • void clearCache();
  • Configuration getConfiguration();
  • Connection getConnection();
  • <T> T getMapper(Class<T> type);

 

通过 Mapper 实例操作数据库

可以同过 SqlSession 生成 Mapper 类实例,通过 Mapper 实例调用 Mapper 中定义的各种数据库操作方法。

PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
Person p=mapper.selectByPrimaryKey(1);
......

 

通过注解的方式定义数据库操作方法

可以直接在生成的 Mapper 类中额外加入自定义的数据库操作方法。使用注解可以没有 XML 映射文件。

@Select("select * from person where name like #{name}")  
public Person selectPersonByName(String name);

@Select("select * from person where content is not null")
public List<Person> selectPersonWithContent();

 

注解详解

注解 Mapper 示例 

@CacheNamespace(size = 512)  
public interface TestMapper {   
    @SelectProvider(type = TestSqlProvider.class, method = "getSql")  
    @Options(useCache = true, flushCache = false, timeout = 10000)  
    @Results(value = {  
      @Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),  
      @Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR)})  
    public TestBean get(@Param("id")String id);  
  
    @SelectProvider(type = TestSqlProvider.class, method = "getAllSql")  
    @Options(useCache = true, flushCache = false, timeout = 10000)  
    @Results(value = {  
       @Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),  
       @Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR)})  
    public List<TestBean> getAll();  
   
    @SelectProvider(type = TestSqlProvider.class, method = "getByTestTextSql")  
    @Options(useCache = true, flushCache = false, timeout = 10000)  
    @ResultMap(value = "getByTestText")  
    public List<TestBean> getByTestText(@Param("testText")String testText);  
  
    @InsertProvider(type = TestSqlProvider.class, method = "insertSql")  
    @Options(flushCache = true, timeout = 20000)  
    public void insert(@Param("testBean")TestBean testBean);  
  
    @UpdateProvider(type = TestSqlProvider.class, method = "updateSql")  
    @Options(flushCache = true, timeout = 20000)  
    public void update(@Param("testBean")TestBean testBean);  
  
    @DeleteProvider(type = TestSqlProvider.class, method = "deleteSql")  
    @Options(flushCache = true, timeout = 20000)  
    public void delete(@Param("id")String id);  
}  

注解说明

  • @CacheNamespace(size = 512)     定义在该命名空间内允许使用内置缓存,最大值为 512 个对象引用,读写默认是开启的,缓存内省刷新时间为默认 3600000 毫秒,写策略是拷贝整个对象镜像到全新堆(如同 CopyOnWriteList)因此线程安全。
  • @SelectProvider(type = TestSqlProvider.class, method = "getSql") : 提供查询的 SQL 语句,如果你不用这个注解,你也可以直接使用 @Select("select * from ....") 注解,把查询 SQL 抽取到一个类里面,方便管理,同时复杂的 SQL 也容易操作,type = TestSqlProvider.class 就是存放 SQL 语句的类,而 method = "getSql" 表示 get 接口方法需要到 TestSqlProvider 类的 getSql 方法中获取 SQL 语句。
  • @Options(useCache = true, flushCache = false, timeout = 10000) : 一些查询的选项开关,比如 useCache = true 表示本次查询结果被缓存以提高下次查询速度,flushCache = false 表示下次查询时不刷新缓存,timeout = 10000 表示查询结果缓存 10000 秒。更新数据库的操作,需要重新刷新缓存 flushCache = true 使缓存同步
  • @Results(value = { @Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR), @Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR) }) : 表示 sql 查询返回的结果集,@Results 是以 @Result 为元素的数组,@Result 表示单条属性 - 字段的映射关系,如:@Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR) 可以简写为:@Result(id = true, property = "id", column = "test_id"),id = true 表示这个 test_id 字段是个 PK,查询时 mybatis 会给予必要的优化,应该说数组中所有的 @Result 组成了单个记录的映射关系,而 @Results 则单个记录的集合。 
  • @Param("paramName") :全局限定别名,定义查询参数在 sql 语句中的位置不再是顺序下标 0,1,2,3.... 的形式,而是对应名称,该名称就在这里定义。 如果参数类型为模型类,要在 sql 中引用对象里面的属性,使用类似 paramName.id,paramName.textText 的形式,mybatis 会通过反射找到这些属性值。
  • @ResultMap(value = "getByTestText") :重要的注解,可以解决复杂的映射关系,包括 resultMap 嵌套,鉴别器 discriminator 等等。注意一旦你启用该注解,你将不得不在你的映射文件中配置你的 resultMap,而 value = "getByTestText" 即为映射文件中的 resultMap ID(注意此处的 value = "getByTestText",必须是在映射文件中指定命名空间路径)。@ResultMap 在某些简单场合可以用 @Results 代替,但是复杂查询,比如联合、嵌套查询 @ResultMap 就会显得解耦方便更容易管理。 映射文件示例如下,文件中的 namespace 路径必须是使用 @resultMap 的类路径,此处是 TestMapper,文件中 id="getByTestText" 必须和 @resultMap 中的 value = "getByTestText" 保持一致。@ResultMap("mapper_namespace.resultMap_id")
<?xml version="1.0" encoding="UTF-8" ?>    
<!DOCTYPE mapper    
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"    
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">  

<mapper namespace="com.wotao.taotao.persist.test.mapper.TestMapper">
<resultMap id="getByTestText" type="TestBean">
<id property="id" column="test_id" javaType="string" jdbcType="VARCHAR" />
<result property="testText" column="test_text" javaType="string" jdbcType="VARCHAR" />
</resultMap>
</mapper>  

  • @InsertProvider(type = TestSqlProvider.class, method = "insertSql") :用法和含义 @SelectProvider 一样,只不过是用来插入数据库而用的。
  • @UpdateProvider(type = TestSqlProvider.class, method = "updateSql") :用法和含义 @SelectProvider 一样,只不过是用来更新数据库而用的。 
  • @DeleteProvider(type = TestSqlProvider.class, method = "deleteSql") :用法和含义 @SelectProvider 一样,只不过是用来删除数据而用的。 

 

Java 映射文件

使用注解后,可以不再用 XML 映射文件编写 SQL,而是在 java 类中编写。示例如下:

public class TestSqlProvider {  
    private static final String TABLE_NAME = "test";  
    public String getSql(Map<String, Object> parameters) {  
        String uid = (String) parameters.get("id");  
        BEGIN();  
        SELECT("test_id, test_text");  
        FROM(TABLE_NAME);  
        if (uid != null) {  
            WHERE("test_id = #{id,javaType=string,jdbcType=VARCHAR}");}  
        return SQL();}  
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getAllSql() {  
    BEGIN();  
    SELECT(</span>"test_id, test_text"<span style="color: rgba(0, 0, 0, 1)">);  
    FROM(TABLE_NAME);  
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SQL();  
}  

</span><span style="color: rgba(0, 0, 255, 1)">public</span> String getByTestTextSql(Map&lt;String, Object&gt;<span style="color: rgba(0, 0, 0, 1)"> parameters) {  
    String tText </span>= (String) parameters.get("testText"<span style="color: rgba(0, 0, 0, 1)">);  
    BEGIN();  
    SELECT(</span>"test_id, test_text"<span style="color: rgba(0, 0, 0, 1)">);  
    FROM(TABLE_NAME);  
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (tText != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {  
        WHERE(</span>"test_text like #{testText,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    }  
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SQL();  
}  

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String insertSql() {  
    BEGIN();  
    INSERT_INTO(TABLE_NAME);  
    VALUES(</span>"test_id", "#{testBean.id,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    VALUES(</span>"test_text", "#{testBean.testText,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SQL();  
}  

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String updateSql() {  
    BEGIN();  
    UPDATE(TABLE_NAME);  
    SET(</span>"test_text = #{testBean.testText,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    WHERE(</span>"test_id = #{testBean.id,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SQL();  
}  

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String deleteSql() {  
    BEGIN();  
    DELETE_FROM(TABLE_NAME);  
    WHERE(</span>"test_id = #{id,javaType=string,jdbcType=VARCHAR}"<span style="color: rgba(0, 0, 0, 1)">);  
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> SQL();  
}  

}

 

SqlBuilder 和 SelectBuilder

mybatis 提供 SelectBuilder 和 SqlBuilder 这 2 个小工具来帮助我们生成 SQL 语句。SelectBuilder 专门用来生成 select 语句,而 SqlBuilder 则是一般性的工具,可以生成任何 SQL 语句。可通过import static org.apache.ibatis.jdbc.SqlBuilder.BEGIN的方式引入 SqlBuilder 提供的静态方法。

  • BEGIN() 方法表示刷新本地线程,某些变量为了线程安全,会先在本地存放变量,此处需要刷新。
  • SELECT,FROM,WHERE 等方法拼凑 sql 字符串
  • SQL() 方法将返回最终 append 结束的字符串
  • 更复杂的标签还有 JOIN,INNER_JOIN,GROUP_BY,ORDER_BY 等

参数

通过 Map<String, Object> parameters 接收 Mapper 接口中定义的参数。Mapper 接口方法中定义使用了命名的参数如 @Param("testId"),@Param("testText"),Map 中的 key 为参数名,如果参数没有命名,key 为基于 0 的顺序下标。

 

在 Spring 中使用

@Repository("testBaseDAO")  
public class TestBaseDAO {
    ......
    @Autowired  
    public void setTestMapper(@Qualifier("testMapper")TestMapper testMapper) {  
        this.testMapper = testMapper;  
    }  
    ......
}

 

关联查询

模型 | 数据表

Clazz 

int id int c_id
String name varchar c_name
Teacher teacher int teacher_id
List<Student> students  

 

Teacher

int id int t_id
String name varchar t_name

 

Student

int id  int s_id
String name varchar s_name
  int class_id

 

 

一对一关系(A 实体类中有一个 B 实体类的属性 )

使用association标签,可用属性:

  • property     对象属性名
  • javaType    对象属性类型
  • column      对应外键字段名称
  • select        使用另一个查询封装的结果

方式一:嵌套结果

    <select id="getClazz" parameterType="int" resultMap="ClazzResultMap">
        select * from Clazz c, Teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
    </select>
    <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 -->
    <resultMap type="com.demo.models.Clazz" id="ClassResultMap">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" javaType="com.demo.models.Teacher">
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
    </resultMap>

方式二:嵌套查询

     <select id="getClazz" parameterType="int" resultMap="ClazzResultMap">
        select * from Clazz where c_id=#{id}
     </select>
     <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 -->
     <resultMap type="com.demo.Clazz" id="ClazzResultMap">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="refB" column="teacher_id" select="getTeacher"/>
     </resultMap>
     <select id="getTeacher" parameterType="int" resultType="com.demo.Teacher">
        SELECT t_id id, t_name name FROM Teacher WHERE t_id=#{id}
     </select>

 

一对多关联(A 实体类中有一个 B 实体类的集合)

使用collection标签

  • ofType    集合中元素对象类型

方式一:嵌套结果

    <select id="getClazz" parameterType="int" resultMap="ClazzResultMap">
        select * from Class c, Teacher t, Student s where c.teacher_id=t.t_id and c.c_id=s.c_id and c.c_id=#{id}
    </select>
    <resultMap type="com.demo.Clazz" id="ClazzResultMap">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" column="teacher_id" javaType="com.demo.Teacher">
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
        <!-- ofType 指定 students 集合中的对象类型 -->
        <collection property="students" ofType="com.demo.Student">
            <id property="id" column="s_id"/>
            <result property="name" column="s_name"/>
        </collection>
    </resultMap>

方式二:嵌套查询

     <select id="getClazz" parameterType="int" resultMap="ClazzResultMap">
        select * from class where c_id=#{id}
     </select>
     <resultMap type="com.demo.Clazz" id="ClazzResultMap">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" column="teacher_id" javaType="com.demo.Teacher" select="getTeacher"></association>
        <collection property="students" ofType="com.demo.Student" column="c_id" select="getStudent"></collection>
     </resultMap>
     <select id="getTeacher" parameterType="int" resultType="com.demo.Teacher">
        SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
     </select>
     <select id="getStudent" parameterType="int" resultType="com.demo.Student">
        SELECT s_id id, s_name name FROM student WHERE class_id=#{id}
     </select>

 

 

 

调用存储过程

定义存储过程

-- 创建存储过程 (查询得到男性或女性的数量, 如果传入的是 0 就女性否则是男性)
DELIMITER $
CREATE PROCEDURE mybatis.ges_user_count(IN sex_id INT, OUT user_count INT)
BEGIN  
IF sex_id=0 THEN
SELECT COUNT(*) FROM mybatis.p_user WHERE p_user.sex='' INTO user_count;
ELSE
SELECT COUNT(*) FROM mybatis.p_user WHERE p_user.sex='' INTO user_count;
END IF;
END 
$

-- 调用存储过程
DELIMITER ;
SET @user_count = 0;
CALL mybatis.ges_user_count(
1, @user_count);
SELECT @user_count;

sql 映射配置

    <!-- 查询得到男性或女性的数量, 如果传入的是 0 就女性否则是男性 -->
    <select id="getUserCount" parameterMap="getUserCountMap" statementType="CALLABLE">
        CALL mybatis.ges_user_count(?,?)
    </select>
    <parameterMap type="java.util.Map" id="getUserCountMap">
        <parameter property="sexid" mode="IN" jdbcType="INTEGER"/>
        <parameter property="usercount" mode="OUT" jdbcType="INTEGER"/>
    </parameterMap>

查询

Map<String, Integer> parameterMap = new HashMap<String, Integer>();
parameterMap.put("sexid", 1);
parameterMap.put("usercount", -1);
sqlSession.selectOne("getUserCount", parameterMap);
Integer result = parameterMap.get("usercount");

 

 

缓存

Mybatis 同时提供了一级缓存和二级缓存的支持。

  • 一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,存储作用域为 SqlSession,当 SqlSession flush 或 close 后,该 Session 的所有 Cache 会被清空。一级缓存默认开启。
  • 二级缓存:默认也是采用 PerpetualCache HashMap 存储,作用域为 Mapper(Namespace),可以自定义存储源,如 Ehcache。
  • 开启二级缓存,Mybatis 配置中加入 <cache/> 元素可开启二级缓存。二级缓存从 cache(mapper.xml 中定义) 中取得,需要调用 session.commit(),数据才会放入 chache 中,二级缓存才有效。
  • 缓存的数据更新机制为:当某作用域(一级缓存 Session/ 二级缓存 Namespaces)进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存会被 clear。
  • 映射语句文件中所有 select 语句都会被缓存,映射文件中所有 insert,update,delete 语句都会刷新缓存。
<cache 
eviction="FIFO"       <!-- 回收策略为先进先出,默认使用 LRU 算法 (最近最少使用)-->
flushInterval="60000" <!--自动刷新时间 60s-->
size="512"            <!-- 可缓存 512 个引用对象, 最大为 1024-->
readOnly="true"/>     <!--只读-->

 

Mybatis3.x 与 Spring4.x 整合

有 3 种常用的整合方式及关键配置

http://blog.csdn.net/bluesky5219/article/details/7066174

  • 数据映射器 (MapperFactoryBean),可不用写映射文件,全采用注解方式提供 sql 语句和输入参数。
     <!--创建数据映射器,数据映射器必须为接口-->
      <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> 
        <property name="mapperInterface" value="com.xxt.ibatis.dbcp.dao.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 
      </bean>
  • 采用 SqlSession 的实现类 SqlSessionTemplate。Mybatis-Spring 中可用 SqlSessionFactoryBean 代替 SqlSessionFactoryBuilder 创建 sessionFactory。
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" /> 
      <!-- 指定 sqlMapConfig 总配置文件,订制的 environment 在 spring 容器中不在生效-->
      <property  name="configLocation"  value="classpath:sqlMapConfig.xml"/>
      <!--指定实体类映射文件,可以指定同时指定某一包以及子包下面的所有配置文件,mapperLocations 和 configLocation 有一个即可,当需要为实体类指定别名时,可指定 configLocation 属性,再在 mybatis 总配置文件中采用 mapper 引入实体类映射文件 -->
      <property  name="mapperLocations"  value="classpath*:com/xxt/ibatis/dbcp/**/*.xml"/> 
  </bean>
  • 采用抽象类 org.mybatis.spring.support.SqlSessionDaoSupport 提供 SqlSession
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 
      <constructor-arg index="0" ref="sqlSessionFactory" /> 
</bean>

 

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

mybatis 相关依赖

  • mybatis
  • mybatis-spring
  • Spring 相关依赖

spring-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  <!-- 配置数据源 -->
  <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_username}" />
        <property name="password" value="${jdbc_password}" />
        ......
  </bean>

<!-- 配置 Mybatis sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 实例化 sqlSessionFactory 时需要使用上述配置好的数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描 me/gacl/mapping/ 目录下的所有 SQL 映射 xml 文件, 无需 Configuration.xml 里的手工配置-->
<property name="mapperLocations" value="classpath:com/demo/mappers/*.xml" />
     <!-- <property name="configLocation" value="classpath:configuration.xml" /> -->
</bean>

<!-- 配置 Mybatis Mapper 映射接口扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描 com.demo.mappers 包以及它的子包下的所有映射接口 -->
<property name="basePackage" value="com.demo.mappers" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
  <!-- 另一种配置方式:data OR mapping interface,此处忽略 -->  
<!--<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">  
  <property name="sqlSessionFactory" ref="testSqlSessionFactory" />  
<property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" />  
</bean> --> 

  <!-- 配置 Spring 的事务管理器 -->
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
  </bean>

  <!-- 注解方式配置事务 -->
  <!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->

  <!-- 拦截器方式配置事务 -->
  <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />
        <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException" />
        <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
        <tx:method name="find*" propagation="SUPPORTS" />
        <tx:method name="get*" propagation="SUPPORTS" />
        <tx:method name="select*" propagation="SUPPORTS" />
        <!-- <tx:method name="*" propagation="SUPPORTS" /> -->
    </tx:attributes>
  </tx:advice>

  <!--把事务控制在 Service 层 -->
  <aop:config>
   <!-- execution(public * com.demo.service.*.*(..) ) -->
   <aop:pointcut id="transactionPointcut" expression="execution(* com.demo.service..*Impl.*(..))" />   
   <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
  </aop:config>
</beans>

 

创建 Service 接口

public interface PersonService
{
  List<Person> getAllPerson();}

创建 Service 实现类

@Service("IdOfPersonService")   //自动在 DI 容器中注册成 Service 组件
public class PersonServiceImpl implements PersonService
{
      @Autowired  PersonMapper personMapper;   //dao 依赖注入
      @Override public List<User> getAllPerson() 
       {
            return personMapper.selectByExampleWithBLOBs(null);}  
}

创建控制器类(不使用 Spring Servlet 进行分发控制)

@WebServlet("/persons")  //Servlet3.0 提供的注解,将一个继承了 HttpServlet 类的普通 java 类标注为一个 Servlet,不需要在 web.xml 中配置
public class PersonServlet extends HttpServlet 
{
private PersonService personService; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//获取所有的用户信息 List<Person> persons = userService.getAllPersons(); request.setAttribute("persons", persons); request.getRequestDispatcher("/index.jsp").forward(request, response); }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在Servlet初始化时获取Spring上下文对象(ApplicationContext)</span>
    ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getServletContext());
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从ApplicationContext中获取userService</span>
    userService = (UserServiceI) ac.getBean("IdOfPersonService"<span style="color: rgba(0, 0, 0, 1)">);
}

}

Spring 注解的控制器(Web.xml 中配置 Spring Servlet,其中 Spring 分发控制)

@Controller
@RequestMapping("/persons")
public class CaseResultAnalyzeController {
    @Autowried private PersonService personService;
    @RequestMapping
    public ModelAndView index()
    {
        ModelAndView mv=new ModelAndView();
        mv.addObject("persons", personService.getAllPersons());
        mv.setViewName("/index.jsp");
        return mv;
    }
}

 

 

 

更多配置

Mybatis 配置文件和数据库连接配置分离

单独创建 db.properties 文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb
name=xxxx
password=xxxx

mybatis 配置文件中引入 db.properties 文件

<?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="db.properties"/>
    <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="${name}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>
  ......
</configuration>

 

定义实体类别名

mybatis 配置文件的 configuration 节点下加入 typeAliases 元素

<typeAliases>
    <!-- 为单个类设置别名 -->
    <typeAlias type="com.demo.Person" alias="_Person"/>
    <!-- 为整个包下的类设置别名,默认的别名就是不带包名的类名 -->
    <package name="com.demo"/>
</typeAliases>

 

然后在 sql 映射的 XML 中就可以使用别名代替 model 类名了

<insert id="addUser" parameterType="_Person">
    insert into person(id,name) values(#{id},#{name})
</insert>

 

模型类和数据表字段名不一致

方式一:

在 Mapper 的 XML 文件中使用 resultMap 元素定义映射关系。sql 语句定义中引用映射关系。

<resultMap type="com.demo.Person" id="personResultMap">
    <!-- 主键字段映射 -->
    <id property="id" column="person_id"/>
    <!-- 非主键字段映射 -->
    <result property="name" column="person_no"/>
</resultMap>
<select id="selectPersonResult" parameterType="int" resultMap="personResultMap">
  select * from person where person_id=#{id}
</select>

方式二:

使用 sql 语句生成和模型对象属性名相同的字段别名

<select id="selectOrder" parameterType="int" resultType="com.demo.Person">
    select person_id id, person_name name from person where person_id=#{id}
</select>

 

模糊查询判断参数非空

<isNotEmpty prepend="and" property="name">
    NAME like '%'||#name#||'%'
</isNotEmpty>

这种方式无法走索引(走索引只限于 like 'xxx%' 的形式,%xxx 和 %xxx% 都不行),也有说有时候会遇到检索不到数据的(参考

 

 

参考文档

http://www.cnblogs.com/xdp-gacl/tag/MyBatis%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/

http://www.cnblogs.com/ibook360/archive/2012/07/16/2594056.html

http://www.cnblogs.com/fsjohnhuang/category/618850.html   (MyBatis 魔法堂)

 

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

 从 Ibatis 过渡到 Mybatis- 比较 Mybaits 较与 Ibatis 有哪些方面的改进

1. 全局文件的配置

         MyBatis 全局配置文件的各主要元素基本和 iBatis 相同,只是在用法和个别名称上做了调整。

DTD 约束不同

MyBatis 的 DTD 文件已经包含在发布包下的 mybatis-3.0.x.jar 包中。iBatis 配置文件的根元素是 <sqlMapConfig>,MyBatis 使用的是 <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>
   ......
    </configuration>

SqlSessionFactory 代替 SqlMapClient

      MyBatis 能够根据配置信息和数据库建立连接,并应用给定的连接池信息和事务属性。MyBatis 封装了这些操作,最终暴露一个 SqlSessionFactory 实例供开发者使用,从名字可以看出来,这是一个创建 SqlSession 的工厂类,通过 SqlSession 实例,开发者能够直接进行业务逻辑的操作,而不需要重复编写 JDBC 相关的样板代码。根据全局配置文件生成 SqlSession 的代码如下:

   Reader reader = Resources.getResourceAsReader("Configuration.xml");
   SqlSessionFactory sqlSessionFactory =
   new SqlSessionFactoryBuilder().build(reader);
     SqlSession sqlSession = sqlSessionFactory.openSession();

   Resources 是 MyBatis 提供的一个工具类,它用于简化资源文件的加载,它可以访问各种路径的文件。Mybatis 现在已经没有 SqlMapClient 了,使用的则是 SqlSession. 在原来的基础上加了像 selectMap,selectList,selectOne 这样的方法,使用更方便了。

事务管理器和数据源配置方式 

ibatis 配置事务管理器和数据源的方式如下:

   <transactionManager type="JDBC" >
     <dataSource type="SIMPLE">
       <property name="JDBC.Driver" value="${driver}"/>
       <!-- 其他数据源信息省略 -->
     </dataSource>
    </transactionManager>

 在 MyBatis 中配置事务管理器和数据源的方式:

<environments default="demo">
   <environment id="demo">
       <transactionManager type="JDBC"/>
       <dataSource type="POOLED">
           <property name="JDBC.Driver" value="${driver}"/>
           <!-- 其他数据源信息省略 -->
       </dataSource>
   </environment>
</environments>    

 

 指定映射文件方式      

在 iBatis 中指定映射文件的方式如下:

   <sqlMap resource=... />
   <sqlMap resource=... />
    <sqlMap resource=... />

在  MyBatis  中指定映射文件的方式:

    <mappers>
       <mapper resource=... />
       <mapper resource=... />
     </mappers>

 

 MyBatis 可以通过代码进行配置

   DataSource ds = …… // 获取一个 DataSource
   TransactionFactory txFactory = new JdbcTransactionFactory();
   Environment env = new Environment("demo", txFactory, ds);
   Configuration cfg = new Configuration(env);
   cfg.addMapper(UserInfoMapper.class);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(cfg);

    结合前面的配置文件,很容易理解这段代码的意思,不过,需要注意的是 Configuration 的 addMapper() 方法,该方法的参数通常是一个接口,可以在接口里面定义若干方法,在方法上使用注解来指定映射的 SQL 语句。   

     // 映射 SQL 绑定接口
   public interface UserInfoMapper
   {   @Select("select * from userinfo where userid = #{userid}")   public UserInfo getUserInfo(int userid);
   }
   // 接口绑定对应的数据访问方法
   try
   {   //UserInfo userinfo = (UserInfo) sqlSession.selectOne
   ("mybatis.demo.UserInfoMapper.selectUser", 2);
   UserInfoMapper userinfoMapper =
   sqlSession.getMapper(UserInfoMapper.class);
   UserInfo userinfo = userinfoMapper.getUserInfo(1);
   System.out.println(userinfo);
   } finally
   {   sqlSession.close();
    }

 

2. 映射文件中配置  SQL  语句:

  <?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="mybatis.demo.UserInfoMapper">
   <select id="selectUser" parameterType="int"
   resultType="mybatis.demo.UserInfo">
   select * from UserInfo where userid =#{userid}
   </select>
    </mapper>

  在 iBatis 中,namespace 不是必需的,且它的存在没有实际的意义。在 MyBatis 中,namespace 终于派上用场了,它使得映射文件与接口绑定变得非常自然。Ibatis 用的 parameterClass 在 mybatis 中已经永不了了,mybatis 里应该使用 parameterType。另外 resultMap 里面也不能继续使用了改成了 type。

    同时数据类型的声明和 ibatis 有了很大的差别,ibatis 可以像下面这样写

   insert into M_HEALTHSPECIALYTYPE(FCODE,FCHARGE,FTYPECONTENT,FID,FMARK) 
   values (#FCODE:VARCHAR2#,#FCHARGE:VARCHAR2#,#FTYPECONTENT:VARCHAR2#,#FID#,#FMARK:VARCHAR2#)

    而在 mybatis 的话一般是这样弄的:

  insert into M_HEALTHSPECIALYTYPE(FCODE,FCHARGE,FTYPECONTENT,FID,FMARK) 
   values (#{FCODE,jdbcType=VARCHAR},#{FCHARGE,jdbcType=VARCHAR},#{FTYPECONTENT,jdbcType=VARCHAR},#{FID},#{FMARK,jdbcType=VARCHAR}) 

 

针对映射文件,首先是一系列的属性名称的改变,这些仅仅是名称的改变,用法和含义并没有发生变化:

· 和全局配置文件一样,由于 DTD 约束发生变化,根元素也由原来的 <sqlMap> 调整为 <mapper>。

· <select> 等元素的 parameterClass 属性改为了 parameterType 属性。

· <select> 等元素的 resultClasss 属性改为了 resultType 属性。

· <parameterMap> 等元素的 class 属性改为了 type 属性。

· <result> 元素的 columnIndex 属性被移除了。

· 嵌套参数由 #value# 改为了 #{value}。

· <parameter> 等元素的 jdbcType 属性取值中,原来的 "ORACLECURSOR" 取值改为了现在的 "CURSOR","NUMBER" 取值改为了 "NUMERIC"。

  

3. 使用  SqlSession  执行映射文件中配置的  SQL  语句

   try
   {   UserInfo userinfo = (UserInfo) sqlSession.selectOne
   ("mybatis.demo.UserInfoMapper.getUser", 2);
   System.out.println(userinfo);
   } finally
   {   sqlSession.close();
 }

       需要注意的是,SqlSession 的使用必需遵守上面的格式,即在 finally 块中将其关闭。以保证资源得到释放,防止出现内存泄露!以上就是一个简单而完整的 MyBatis 程序。其中涉及了全局配置文件,映射文件,构建 SqlSession 对象,执行数据访问操作等四个步骤。

     

4.iBatis/MyBatis 对存储过程的支持.

iBatis  中调用存储过程的方式(通过使用 <procedure> 元素进行存储过程的定义):

  <procedure id="getValues" parameterMap="getValuesPM">
      {? = call pkgExample.getValues(p_id => ?) }
   </procedure>

在 MyBatis 中,<proccedure> 元素已经被移除,通过 <select>、<insert> 和 <update> 进行定义:

  <select id="getValues" parameterMap="getValuesPM" statementType="CALLABLE">  
    {? = call pkgExample.getValues(p_id => ?)}   
  </select>

如上所示,通过 statementType 属性将该语句标识为存储过程而非普通 SQL 语句。

 

总结:

      通过前面的示例可以看出,MyBatis 在编码中的最大的改变就是将一个最常用的 API 由 SqlMapClient 改为 SqlSessionFactory。另外,类型处理器接口也由原来的 TypeHandlerCallback 改为了 TypeHandler。最后 DataSourceFactory 也进行了调整,移动到 org.apache.ibatis.datasource 包下,其中的方法也作了微调。总之,代码层面公开的部分改动较少,不会给开发者造成较大的移植成本。