Mybatis详解(二)Mybatis XML方式的基本用法

1、使用XML方式

MyBatis的真正强大之处在于它的映射语句,由于他的映射语句异常强大,映射器的XML文件就显得相对简单。而MyBatis3.0相比2.0版本的一个最大变化,就是支持使用接口的来调用方法。

我们使用的是SqlSession通过命名空间调用MyBatis方法,我们需要用到命名空间和方法id组成的字符串来调用相应的方法。而当参数多于1个的时候,需要将参数放到一个Map对象中。通过Map传递多个参数,使用起来很不方便。 使用接口调用的方式就会方便很多,MyBatis使用Java的动态代理可以直接通过接口来调用相应的方法,不需要提供接口的实现类,并且也不需要使用SqlSession以通过命名空间间接调用。同时,当有多个参数时,可以通过在参数之前添加@Param("paramName")设置参数的名字,这样我们就可以不用手动构造Map参数了,尤其是在Spring中使用的时候,可以配置为自动扫描所有的接口类,直接将接口注入需要用到的地方。 

<mappers>
    <mapper resource="tk.mybatis.simple.mapper"/>
</mappers>
  1. 这种配置方式会先查找tk.mybatis.simple.mapper包下所有的接口,循环对接口进行如下操作:
  2. 判断接口对应的命名空间是否已经存在,如果不存在就抛出异常,存在进行下来的操作。
  3. 加载接口对应的 XML 映射文件,将接口全限定名转换为路径,例如,将接口tk.mybatis.simple.mapper.UserMapper转换为tk/mybatis/simple/mapper/UserMapper.xml,以.xml为后缀搜索XML资源,如果找到就解析XML。
  4. 处理接口中的注解方法。

① 当只使用XML而不使用接口的时候,namespace的值可以设置为任意不重复的名称。
② 标签的id属性值在任何时候都不能出现英文的句号“.”,并且同一个命名空间下不能出现重复的id
③ 因为接口方法是可以重载的,所以接口中可以出现多个同名但是参数不同的方法,但是XML中id的值不能重复,那么接口中的多有的同名方法都对应着XML中的同一个id的方法。

2、select用法

因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中id的值不能重复,因而接口中的所有同名方法会对应着XML中的同一个id的方法。最常见的用法就是,同名方法中其中的一个方法增加一个 RowBound 类型的参数用于实现分页查询。

XML中的resultType(或resultMap中的type)决定的接口中写的返回值类型,两者要一致。

MyBatis 还提供了一个全局属性mapUnderscoreToCamelCase,通过配置这个属性为true可以自动将以下画线方式命名的数据库列映射到Java对象的驼峰式命名属性中。想要使用该功能,在MyBatis-config.xml中增加如下配置。

注意!:xml中sql语句返回类型最好使用restultMap不要用resultType,因为resultType映射时属性名和列名必须一致。

XML中的select标签的id属性值和定义的接口方法名是一样的。MyBatis就是通过这种方式将接口方法和XML中定义的SQL语句关联到一起的。

标签和属性的作用:

  • <select>:映射查询语句使用的标签。
  • id:命名空间中唯一标识符,可用来代表这条语句
  • resultMap:用于设置返回值得类型和映射关系。
  • select标签中的select * from sys_user where id = #{id}是查询语句。
  • #{id}:MyBatis SQL中使用预编译参数的一种方式,大括号中的id是传入的参数名。

resultMap标签包含的属性
jdbcType:列对应的数据库类型。插入、更新、删除操作可能为空的列进行处理。这是JDBC jdbcType的需要,不是MyBatis的需要。

  • id:必填,并唯一,在select标签中resultMap指定的值即为此id所设置的值。
  • type:必填用于配置查询列所映射到的Java对象类型。
  • extends:选填,可以配置当前的resultMap继承自其它的resultMap,属性值为继承的resultMap的id。
  • autoMapping:选填,可选值为true或false,用于配饰是否启用非映射字段(没有在resultMap中配置的字段)的自动映射功能,该配置可以覆盖全局的autoMappingBehavior配置。
/**

 * 生成sqlSessionFactory实例

 * 基础测试类

 */

public class BaseMapperTest {

     private static SqlSessionFactory sqlSessionFactory;

     @BeforeClass
     public static void init(){

          try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
          } catch (IOException ignore) {
            ignore.printStackTrace();
          }

     }
     
     public SqlSession getSqlSession(){
          return sqlSessionFactory.openSession();
     }

}


public class UserMapperTest extends BaseMapperTest {

     @Test
     public void testSelectById(){

          //获取 sqlSession
          SqlSession sqlSession = getSqlSession();
          try {
              //获取 UserMapper 接口
              UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

              //调用UserMapper 接口中的 selectById 方法,查询 id = 1 的用户
              SysUser user = userMapper.selectById(1l);

              //user 不为空
              Assert.assertNotNull(user);

              //userName = <u>admin</u>
              Assert.assertEquals("admin", user.getUserName());
            } finally {
              //不要忘记关闭 sqlSession
              sqlSession.close();
          }

     }

}

3、insert用法

先看<insert>元素,这个标签包含如下属性。

  • id:命名空间中的唯一标识符,可用来代表这条语句。
  • parameterType:即将传入的语句参数的完全限定类名或别名。这个属性是可选的,因为MyBatis可以推断出传入语句的具体参数,因此不建议配置该属性。
  •  flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存。· timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。
  • statementType:对于STATEMENT、PREPARED、CALLABLE,MyBatis会分别使用对应的 Statement、PreparedStatement、CallableStatement,默认值为PREPARED。· useGeneratedKeys:默认值为 false。如果设置为 true,MyBatis 会使用 JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。
  • keyProperty:MyBatis通过getGeneratedKeys获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表。
  • keyColumn:仅对INSERT和UPDATE有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如 PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
  • databaseId:如果配置了databaseIdProvider(4.6节有详细配置方法),MyBatis会加载所有的不带databaseId的或匹配当前databaseId的语句。如果同时存在带databaseId和不带databaseId的语句,后者会被忽略。此处<insert>中的 SQL 就是一个简单的 INSERT 语句,将所有的列都列举出来,在values中通过#{property}方式从参数中取出属性的值。

为了防止类型错误,对于一些特殊的数据类型,建议指定具体的 jdbcType 值。例如headImg指定BLOB类型,createTime指定TIMESTAMP类型。特别说明!BLOB对应的类型是ByteArrayInputStream,就是二进制数据流。由于数据库区分date、time、datetime类型,但是Java中一般都使用java.util.Date类型。因此为了保证数据类型的正确,需要手动指定日期类型,date、time、datetime对应的JDBC类型分别为DATE、TIME、TIMESTAMP。

数据库的datetime类型可以存储DATE(time部分默认为00:00:00)和TIMESTAMP(时间戳)这两种类型的时间,不能存储TIME类型的时间。

使用JDBC方式返回主键自增的值:

用数据库内部自动生成的主键值给指定的列 (id) 赋值。
下面的insert语句当中不用再写id列列名和值。

<insert id="insert2" useGeneratedKeys="true" keyProperty="id"></insert>

keyColumn :  数据库表中主键列的名字。
当需要设置多个属性时, 使用逗号隔开 这种情况下通常还需要设置 keyColumn 属性, 按顺序指定数据库的列。
keyProperty: 主键列对应的java类中属性名。
useGeneratedKeys = true使用自动生成的主键值给指定列赋值。

使用selectKey返回主键的值

有些数据库(如 Oracle) 不提供主键自增的功能, 而是使用序列得到一个值。 使用<selectKey>标签来获取主键的值, 这种方式不仅适用于不提供主键自增功能的数据库, 也适用于提供主键自增功能的数据库。

Oracle:

<!-- Oracle 的例子,查询多个列的时候需要 keyColumn -->
<insert id="insertOracle">
	<selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
		  SELECT SEQ_USER.nextval from dual
	</selectKey>
    insert into sys_user(id, user_name, user_password, user_email, 
           user_info, head_img, create_time)
    values(#{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, 
           #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
</insert>

insert语句中要写主键列 (id) insert into sys_user(id,...)

原因  在Oracle数据库中,需要先从序列获取id值, 然后将值赋给入参,再插入到数据库中。order = "BEFORE"

MYSQL

<insert id="insert3">
	insert into sys_user(
		user_name, user_password, user_email, 
		user_info, head_img, create_time)
	values(
		#{userName}, #{userPassword}, #{userEmail}, 
		#{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
	<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
		SELECT LAST_INSERT_ID()
	</selectKey>
</insert>

insert语句中不需要写主键列 (id) insert into sys_user(username,...)

原因 在MySQL数据库中,先执行insert语句,再将获得的主键值插入到表中,order="AFTER"。
keyProperty="id" 应该可以不写。

4、update用法

<update id="updateByPrimaryKeySelective" parameterType="com.bloc.core.entity.User">
    update tbl_user
    <set>
      <if test="userName != null">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="passWord != null">
        pass_word = #{passWord,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="phone != null">
        phone = #{phone,jdbcType=VARCHAR},
      </if>
      <if test="cardCode != null">
        card_code = #{cardCode,jdbcType=VARCHAR},
      </if>
      <if test="showName != null">
        show_name = #{showName,jdbcType=VARCHAR},
      </if>
      <if test="state != null">
        state = #{state,jdbcType=VARCHAR},
      </if>
      <if test="userType != null">
        user_type = #{userType,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="creator != null">
        creator = #{creator,jdbcType=VARCHAR},
      </if>
      <if test="updateTime != null">
        update_time = #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updator != null">
        updator = #{updator,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>

5、delete用法

  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from tbl_user
    where id = #{id,jdbcType=BIGINT}
  </delete>

6、多个接口参数的用法

mapper方法接口有多个参数时,加参数前加@param注解:

@Mapper
public interface GoodsMapper {

    int deleteByPrimaryKey(Long id);

    int insert(Goods record);

    Goods selectByPrimaryKey(Long id);

    int updateByPrimaryKeySelective(Goods record);

    //mapper方法接口有多个参数时,加参数前加@param注解:
    List<Goods> findGoodsListByParam(@Param("name") String name,
                                     @Param("code") String code,
                                     @Param("state") String state,
                                     @Param("startTime") String startTime,
                                     @Param("endTime") String endTime,
                                     @Param("platform") String platform);
}

匹配格式就是,可用的参数是[0,1,...,param1,param2,...],也就是说我们将代码修改为:

WHERE u.id = #{0} AND r.enabled = #{1} 或者 WHERE u.id = #{param1} AND r.enabled = #{param2}

这么使用是可以测试通过的,不过这样使用,代码阅读起来不够友好,因此并不推荐这么使用。

7、mybatis代码自动生成工具

在pom.xml文件中添加Mybatis逆向工程配置:

<!--mybatis逆向工程-->
<plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.2</version>
    <configuration>
        <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
        <verbose>true</verbose>
        <overwrite>true</overwrite>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>
    </dependencies>
</plugin>

在项目的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>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="false" />
        </commentGenerator>
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        
             <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/data?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true&amp;serverTimezone=Asia/Shanghai"
                        userId="root"
                        password="root">

        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成PO类的位置 -->

        <javaModelGenerator targetPackage="com.test.core.entity" targetProject=".\src\main\java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="main.resources.sqlmap" targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.test.core.mapper.user" targetProject=".\src\main\java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 指定数据库表 -->
        <table tableName="tbl_user" domainObjectName="User" />
        <!-- 有些表的字段需要指定java类型 <table schema="" tableName=""> <columnOverride column=""
            javaType="" /> </table> -->
    </context>
</generatorConfiguration>

然后执行工具创建代码:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值