【MyBatis】MyBatis单表操作

MyBatis单表操作

前言

在前面一小节中,介绍了MyBatis以及MyBatis的简单操作,并且简单地分析了MyBatis的工作机制,接下来这一小节,我们来学习MyBatis的单表操作,包括简单的增删改查

MyBatis单表操作

在本小节中,依然沿用上一小节所使用的环境以及资源

增加数据

CountryMapper.xml中加入下面插入代码

<insert id="insertCountry">
    insert into 
    country(country_name, country_code)
    values (#{countryName}, #{countryCode})
</insert>

CountryMapper.java中加入代码

int insertCountry(Country country);

测试代码如下

@Test
public void testInsertCountry() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CountryMapper countryMapper = sqlSession.getMapper(CountryMapper.class);

    Country country = new Country();
    country.setCountryCode("SGP");
    country.setCountryName("新加坡");

    int result = countryMapper.insertCountry(country);
    // 默认情况是不自动提交事务的,需要手动提交或者在配置文件中设置自动提交
    sqlSession.commit();
    Assert.assertEquals(1, result);
}

上面的操作基本上没有问题,但是如果我们想插入数据的时候顺便回到自增的主键,那还需要多做一点修改

CountryMapper.xml

<insert id="insertCountry" useGeneratedKeys="true" keyProperty="id">...</insert>

userGeneratedKyes="true"表示使用数据库的自增主键,需要注意的是,只能使用一部分支持自增主键的数据库如MySQL,keyProperty=""指定对应的属性

如果是在不支持自增主键的数据库,如Oracle,则需要采用下面的方式

<selectKey keyColumn = "主键列" resultType ="主键类型" keyProperty="id" order="BEFORE/AFTER">
    SELECT SQL LIKE: 
        MySQL: select LAST_INSERT_ID()
        Oracle: select SEQ_ID.nextval from dual
</selectKey>

在selectKey中,需要根据具体的数据库来选择对应的获取主键的操作

order="before/after"需要根据具体的数据库来选择,有的是先生成主键再插入,有的是插入后再生成主键

上面的两种情况中,如果主键列是由多个字段组成,则多个字段之间使用,分隔即可

在上面的插入情况中,我们是使用对象插入的,或者说,是使用一个参数插入的,在MyBatis中,如果是单个参数,可以不同做其他操作,如果是多个参数,为了在SQL中获取参数,还需要额外的一些操作,如果简单的按照上面的操作,是无法成功的,如下

<insert id="insertCountryByNameAndCode">
        insert into country(country_name, country_code)
            values (#{countryName}, #{countryCode})
</insert>
int insertCountryByNameAndCode(String countryName, String countryCode);

执行结果

org.apache.ibatis.exceptions.PersistenceException:
# ....
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'countryName' not found. Available parameters are [arg1, arg0, param1, param2]

可以看到,MyBatis提示我们使用arg0, arg1或者param1, param2这种方式,但实际上这种方式不太好,因为在SQL中无法看出插入的数据是哪个。有两种解决方案,一种是将参数封装到一个map中,key就是参数的名称,value是参数的值,但这种方式比较麻烦,而且还需要手动构造一个map对象,另一种方案是采用下面的方式

int insertCountryByNameAndCode(@Param("countryName") String countryName, @Param("countryCode") String countryCode);

也就是使用@Param("NAME")来指定参数的名称,这种方式是比较推荐的,当然,这种方式本质也是构造一个map,只是由MyBatis来构造,不用我们自己动手。

删除数据

删除数据的情况跟插入数据是类似的,只需要在CountryMapper.xml中加入对应的SQL,然后在CountryMapper.java中加入对应的操作接口即可

<delete id="deleteCountryByCountryCode">
        delete from country
        where country_code = #{countryCode}
</delete>
int deleteCountryByCountryCode(String countryCode);

测试的操作同上,这里就不展开了

修改数据

修改数据的操作也基本同上,可以通过构造对象作为参数,也可以传入多个参数,传入多个参数则使用@Param("")指定参数名称即可

<update id="updateCountryNameByCountryCode">
        update country
        set country_name = #{countryName}
        where country_code = #{countryCode}
</update>
int updateCountryNameByCountryCode(Country country);

测试的操作基本同上,这里就不展开了

查询数据

查询数据是增删改查这几个操作中使用频率最高的,也是操作方式中比较丰富的一个操作,同时也是MyBatis方便性最能体现的一个部分,在查询操作中,通常数据库返回给我们的是一行行的数据,在JDBC操作中,我们需要手动将一行行的数据封装到对象中,而在MyBatis中,这些操作通常只需要指定一个resultType或者一个resultMap,MyBatis就会自动将其封装到对象中,这在复杂操作中比较好用。

<select id="selectCountryByCountryCode">
    select id,
        country_name,
        country_code
    from country
    where country_code = #{country_code}
</select>
Country selectCountryByCountryCode(String countryCode);

当测试上面的操作时,会出现抛出下面的异常

Caused by: org.apache.ibatis.executor.ExecutorException: 
A query was run and no Result Maps were found for the Mapped Statement 'mapper.CountryMapper.selectCountryByCountryCode'.  
It's likely that neither a Result Type nor a Result Map was specified.

由于MyBatis从数据库中获取的是一行行的数据,它并不知道要怎么封装这些数据,所以我们需要告诉它怎么封装这些数据,方法有两个,一个是指定resultType,这通常适用于比较简单的情况,另一个是resultMap,适用于比较复杂的情况

所以只需要将上面的xml修改成下面的xml即可

<select id="selectCountryByCountryCode" resultType="domain.Country">
        select id,
            country_name,
            country_code
        from country
        where country_code = #{country_code}
</select>

如果有在前面指定typeAlias,则可以直接使用类名,否则就需要使用类的全限定名

当然,上面修改后不会抛出异常,但是查询出来的对象字段除了id之外,其他的全是null,Country{id=2, countryName='null', countryCode='null'},原因很简单啦,就是字段没对应上,country_namecountryName之间对不上,解决方法有两种,一种是开启MyBatis的下划线转驼峰功能

config.xml

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true" />
</settings>

这种方式适用于数据库表字段和对象字段之间均能对应上的情况,如果对应不上,则可以使用下面的方式,通过SQL的别名方式

<select id="selectCountryByCountryCode" resultType="domain.Country">
        select id,
            country_name as CountryName,
            country_code as CountryCode
        from country
        where country_code = #{country_code}
</select>

通过上面的两种方式之一修改之后就没问题啦

上面我们提到,可以通过resultType来封装结果集,也可以通过resultMap来封装,下面介绍下resultMap的使用

<select id="selectCountryByCountryCode" resultMap="countryMap">
    select id, country_name, country_code
    from country
    where country_code = #{country_code}
</select>

<!--定义resultMap-->
<resultMap id="countryMap" type="domain.Country">
    <!--封装属性-->
    <id property="id" column="id" />
    <result property="countryName" column="country_name"/>
    <result property="countryCode" column="country_code"/>
</resultMap>

resultMap中有几个需要注意的地方
1. 尽量指定<id>,由于是将一行行的数据对应到对象中,那么就可能出现多行数据相同的情况,而这个时候MyBatis会将其对应到同一个对象中,如果指定了id,那么直接根据id字段的值来比较,如果没有,则根据所有的字段来比较,比较一个字段总是比比较多个字段高效的嘛
2. 在resultMap的字标签中,均可以使用javaType=""以及jdbcType=""这两个类型,当对象的字段跟数据库中字段出现差异的时候,就需要显式指定了,比如Date对象对应的应该是TIMESTAMP而不是数据库中的Date,这个时候就需要指定jdbcType="TIMESTAMP"
3. resultMap中还可以嵌套collectionassociation等字标签,下一节将详细介绍这一部分内容

总结

在本小节中,我们主要学习了MyBatis的单表操作:增删改查,其中需要注意的是如果传入的时候有多个参数,则推荐使用@Param("")指定参数名称,如果需要获取插入的数据的主键,可以根据数据库来使用userGeneratedKey=""或者<selectKey>来获取,在封装数据集到对象的时候,可以使用resultType或者resultMap,而且必须指定一种的一种,也只能使用一种,resultType适用于比较简单的情况,resultMap使用与比较复杂的情况,关于resultMap的更多用法我们将在下节进行详细学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值