【MyBatis系列3】最全MyBatis中XML映射⽂件(Mapper)标签分析及⽰例
前⾔
MyBatis的强⼤之处就在于它的映射器⽂件,⽽这也正是MyBatis的魔⼒所在,对于任何MyBatis的使⽤者来说,MyBatis的映射⽂件是必须要掌握的。
Mapper⽂件标签
Mapper中⼀个提供了9个顶层标签,除了1个已经过期的我们不需要去了解,另外8个都是必须要掌握的,只要熟练掌握了标签的使⽤,使⽤MyBatis才能如鱼得⽔。接下来我们就⼀个个来分析⼀下这些标签的使⽤。
<cache> – 该命名空间的缓存配置。
<cache-ref> – 引⽤其它命名空间的缓存配置。
<resultMap> – 描述如何从数据库结果集中加载对象,是最复杂也是最强⼤的元素。
<parameterMap> – ⽼式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使⽤⾏内参数映射。⽂档中不会介绍此元素。
<sql> – 可被其它语句引⽤的可重⽤语句块。
<insert> – 映射插⼊语句。
<update> – 映射更新语句。
<delete> – 映射删除语句。
<select> – 映射查询语句。
select
select⽤来映射查询语句,是我们使⽤最多的⼀种标签,也是最复杂的⼀种标签。⽐如下⾯就是⼀个简单的select标签的使⽤
<select id="listUserByUserName" parameterType="String" resultType="lwUser">
select user_id,user_name from lw_user where user_name=#{userName}
</select>
select标签内,提供了⼀些⼆级标签,下⾯就列举出了全部的⼆级标签:
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY"
databaseId="mysql"
resultOrdered="false"
resultSets="xxx,xxx"
lang="">
</select>
id
必选标签。同⼀个命名空间⾥⾯的唯⼀标识符,如果需要被外部接⼝调⽤,则需要和Mapper接⼝中的⽅法名保持⼀致。
parameterType
可选标签。参数类的完全限定名或别名,上⾯⽰例中的表⽰我们传⼊的参数是⼀个String类型(关于别名如果不清楚的可以点击这⾥)。如果不写这个属性的话,MyBatis在解析xml ⽂件的时候会默认设为unset,
然后根据TypeHandler推断出参数类型。如果有多个参数的情况下建议还是不写这个参数,否则可能会出现参数类型转换错误
parameterMap
这是⼀个过期的属性,我们不做讨论。
resultType
⾮必选标签。注意:这⾥的⾮选是因为resultType和resultMap不能并存,两者能且只能选择⼀个。主要是⽤来定义⼀个返回结果集对象的全限定名或者别名。如果接收参数是⼀个集合,那么这⾥定义的就是集合中可以包含的类型,⽽并不是集合本⾝。
⽐如⽰例中的写法,那么对应Mapper接⼝中,适⽤于以下两种语句:
LwUser listUserByUserName(@Param("userName") String userName);
List<LwUser> listUserByUserName(@Param("userName") String userName);
resultMap
⾮必选标签。注意这⾥的⾮选是因为resultType和resultMap不能并存,两者能且只能选择⼀个。resultMap类型的结果集映射,是MyBatis最强⼤的特性,在这⾥我们不展开,过两天会有⼀篇单独介绍MyBatis⼀对⼀和⼀对多等复杂查询时候会单独介绍该属性。后续介绍。
flushCache
可选标签。设置为 true时,任何时候只要语句被调⽤,都会导致本地缓存和⼆级缓存都会被清空,默认值:false。
useCache
可选标签。设置为 true时将会导致本条语句的结果被⼆级缓存,对 select 标签语句默认值为true,对insert,delete,update等语句默认是false。
timeout
可选标签。这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。
fetchSize
可选标签。这是尝试影响驱动程序每次批量返回的结果⾏数和这个设置值相等。默认值为 unset(依赖驱动)。注意这个只是尝试,假如把fetchSize设置为10万,⽽数据库驱动最⾼只⽀持到5w,那么也会只能返回5w数据
statementType
可选标签。可以选择:STATEMENT,PREPARED 或 CALLABLE 中的⼀个,这会让 MyBatis 分别使⽤Statement,PreparedStatement 或 CallableStatement,默认值是PREPARED,也就是使⽤预编译PreparedStatement 语句。
resultSetType
可选标签。可以选择以下三种类型中的⼀个,默认为unset(依赖驱动)。
FORWARD_ONLY:只允许游标向前访问
SCROLL_SENSITIVE:允许游标双向滚动,但不会及时更新数据,也就是说如果数据库中的数据被修改过,并不会在resultSet中体现出来
SCROLL_INSENSITIVE:许游标双向滚动,如果数据库中的数据被修改过,会及时更新到resultSet
上⾯的解释可能有些⼈还是看不明⽩,我们先来看⼀段JDBC读取结果集的操作:
⽽MyBatis只是把这些操作封装了,底层实际上还是这个操作,rs.next()游标向前滚,其实还有⼀个rs.previous()表⽰游标可以向后滚。
所以FORWARD_ONLY只允许向前滚,访问过的数据就会释放内存,在某些场景中可以提升性能。
后⾯那两个都是允许双向滚动,所以即使访问过得数据,内存也不能释放。这两个的区别就是⼀个对数据敏感,⼀个对数据不敏感。
对数据不敏感就是说当我们查询出结果之后,会将整个结果集都缓存在内存中,假如有⼀条数据还没读取到(还在while循环中)这时候有另外⼀个线程修改了这条数据,那么当我们后⾯读取这条数据的时候,还是读取到修改之前的。
对数据敏感就是说当我们查询出结果之后,只会缓存⼀个rowid,⽽并不会缓存整条数据,假如有⼀条数据还没读取到(还在while循环中)这时候有另外⼀个线程修改了这条数据,那么当我们后⾯读取这条数据的时候,会根据rowid去查询数据,查询到的就是最新的数据。不过需要注意的是,因为delete的时候数据其实还在,只是打了个标记,所以如果⼀条数据被删除了,是体现不出来的。同理,insert也不影响,因为查询出来的数据不包含insert数据的rowid。
如果对于MySQL的InnoDB引擎的MVCC机制,那么数据肯定是不会敏感的,因为其他事务改了当前事务也看不到。
databaseId
可选标签。数据库⼚商id(如果配置了数据库⼚商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略),详细了解,可以。
resultOrdered
可选标签。这个设置仅针对嵌套结果 select 语句适⽤。如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回⼀个主结果⾏的时候,就不会发⽣有对前⾯结果集的引⽤的情况。这就使得在获取嵌套的结果集的时候不⾄于导致内存不够⽤。默认值: false 。
resultSets
可选标签。这个设置仅对多结果集的情况适⽤,它将列出语句执⾏后返回的结果集并每个结果集给⼀个名称,名称是逗号分隔的。
lang
⾃定义语⾔,这个我也没⽤过,所以就不介绍了
insert
insert⽤来映射插⼊语句。以下就是⼀个insert标签的全部⼆级标签:
<insert
id="insertLwUser"
parameterType="lwUser"
parameterMap="deprecated"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20"
databaseId="mysql"
lang="">
</insert>
有⼀些标签和select语句是重复的就不在重复介绍,主要来关注⼀下其他标签。
useGeneratedKeys
可选标签。配置为true时,MyBatis会使⽤JDBC的getGeneratedKeys⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的⾃动递增字段),默认值为false。
keyProperty
可选标签。唯⼀标记⼀个属性,MyBatis会将通过getGeneratedKeys 的返回值或者通过insert 语句的selectKey ⼦元素设置它的键值,默认值是unset 。如果希望得到多个⽣成的列,也可以是逗号分隔的属性名称列表
注意:⾼版本的mybatis⽀持批量插⼊数据的时候返回多条数据的主键ID,低版本的只⽀持插⼊⼀条数据的时候返回该条数据的主键ID
keyColumn
通过⽣成的键值设置表中的列名,这个设置仅在某些数据库(像PostgreSQL)是必须的,当主键列不是表中的第⼀列的时候需要设置。如果希望得到多个⽣成的列,也可以是逗号分隔的属性名称列表
获取⾃增主键
获取⾃增主键,可以通过keyProperty来映射
定义⼀个实体类:
package ity;
public class UserAddress {
private int id;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "UserAddress{" +
"id=" + id +
", address='" + address + '\'' +
'}';
}
}
定义⼀个UserAddressMapper.java接⼝:
package batis.mapper;
import ity.UserAddress;
public interface UserAddressMapper {
int insertUserAddress(UserAddress userAddress);
}
注意:这⾥参数如果直接只有⼀个的话可以不适⽤@Param注解,这样在xml⽂件中可以直接使⽤JavaBean内的属性名。如果使⽤了@Param注解,如下:
int insert(@Param("userAddress") UserAddress userAddress);
那么xml⽂件中就可以使⽤#{userAddress.属性名}来获取属性JavaBean内的属性
定义⼀个l映射⽂件(keyProperty="id"表⽰把主键的值设置到参数UserAddress类中的属性id):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd">
<!-- 命名空间就是对应的mapper接⼝ -->
<mapper namespace="batis.mapper.UserAddressMapper">
<insert id="insertUserAddress" parameterType="ity.UserAddress" useGeneratedKeys="true"
keyProperty="id">
insert into lw_user_address (address) values (#{address})
</insert>
</mapper>
<!--要加载的xml⽂件-->
<mappers>
<mapper resource="org/tuniu/mybatis/l"></mapper>
</mappers>
也可以这么写(⼀劳永逸):
<mappers>
<package name="batis.mapper"/>
</mappers>
将mapp接⼝和mapper对应的xml进⾏放⼊同⼀个⽂件夹:
然后写⼀个测试类:
package batis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import ity.UserAddress;
import batis.mapper.UserAddressMapper;
import java.io.IOException;
import java.io.InputStream;
public class TestMyBatisInsert {
public static void main(String[] args) throws IOException {
String resource = "l";
//读取mybatis-config配置⽂件
InputStream stream = ResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream, "dev");
//创建SqlSession对象
SqlSession session = sqlSessionFactory.openSession();
try {
UserAddress userAddress = new UserAddress();
userAddress.setAddress("⼴东深圳");
UserAddressMapper mapper = Mapper(UserAddressMapper.class);
int count = mapper.insertUserAddress(userAddress);
sessionmit();
System.out.println("插⼊成功数:" + count);
System.out.println("插⼊数据的主键为:" + Id());
} finally {
if (null != session) {
session.close();
}
}
}
}
输出结果(成功获取到了插⼊数据的主键):
获取⾃增主键(多条)
<insert id="insertUserAddressList" parameterType="list" useGeneratedKeys="true"
keyProperty="id">
insert into lw_user_address (address) values
<foreach collection="list" item="item" separator=",">
(#{item.address})
</foreach>
</insert>
UserAddressMapper.class⽂件加⼊:
int insertUserAddressList(List<UserAddress> list);
测试类:
package batis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import ity.UserAddress;
import batis.mapper.UserAddressMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class TestMyBatisInsert {
public static void main(String[] args) throws IOException {
String resource = "l";
//读取mybatis-config配置⽂件
spring怎么读取xml文件InputStream stream = ResourceAsStream(resource);
//创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream, "dev");
//创建SqlSession对象
SqlSession session = sqlSessionFactory.openSession();
try {
UserAddress userAddress = new UserAddress();
UserAddress userAddress1 = new UserAddress();
UserAddress userAddress2 = new UserAddress();
userAddress.setAddress("⼴东深圳");
userAddress1.setAddress("⼴东珠海");
userAddress2.setAddress("⼴东汕头");
UserAddressMapper mapper = Mapper(UserAddressMapper.class);
// int count = mapper.insertUserAddress(userAddress);
List<UserAddress> list = new ArrayList<UserAddress>();
list.add(userAddress);
list.add(userAddress1);
list.add(userAddress2);
int count = mapper.insertUserAddressList(list);
sessionmit();
System.out.println("插⼊成功数:" + count);
System.out.print("插⼊数据的主键为:");
for (UserAddress address : list) {
System.out.Id()+",");
}
} finally {
if (null != session) {
session.close();
}
}
}
}
返回结果:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论