Java EE数据持久化框架 • 【第2章 MyBatis实现DML操作】

 

全部章节   >>>>


本章目录

2.1 标签

2.1.1 标签简单应用

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

2.1.3 使用标签返回普通主键的值

2.1.4 实践练习

2.2 标签和标签

2.2.1 标签用法

2.2.2 标签用法

2.2.3 删除具有主从关系的主表记录

2.2.4 实践练习

2.3 映射器方法多参数传递

2.3.1 MyBatis默认参数位置

2.3.2 使用Map类型作封装参数

2.3.3 使用注解类型作为参数

2.3.4 实践练习

2.4 MyBatis注解映射

2.4.1 MyBatis注解的基本用法

2.4.2 @Insert注解

2.4.3 @Update注解

2.4.4 @Delete注解

2.4.5 @Provider注解

2.4.4 实践练习

总结:


2.1 <insert>标签

2.1.1 <insert>标签简单应用

在Mybatis中的映射Mappe.xml中,可以使用<insert>标签实现增加数据。

<insert>标签常见属性如下:

属性名

作用

id

对应接口中声明的增加方法名

parameterType

对应增加方法接收参数类型

flushCache

只要语句被调用,都会清空一级缓存和二级缓存

useGeneratedKeys

使用JDBC的getGeneratedKeys()方法取出由数据库生成的主键

keyProperty

通过getGeneratedKeys获取主键值后将要赋值的属性名

 MyBatis<insert>标签实现增加功能步骤如下:

1、在接口中声明增加的抽象方法

2、在接口对应Mapper.xml中添加insert标签映射

 

示例:1、在UserMapper接口中增加一个抽象方法,代表具有增加数据功能

// 返回新增用户的记录数(影响的行数)
int addUser(SysUser user);

SysUser user接收实体对象,封装了要添加的数据

示例:2、在UserMapper.xml中添加该方法对应的sql语句映射: 使用<insert>标签定义增加sql语句

<insert id="addUser">
   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>

id为方法名

#号代表取实体对象中的属性名

特殊类型使用jdbcType说明

示例:3、测试类实现方法调用:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 创建一个SysUser对象
SysUser user = new SysUser();
user.setUserName("test1");
//设置user对象其他属性
// 正常情况下应该读入一张图片存到byte数组中,这里模拟字节数据
user.setHeadImg(new byte[] {1,2,3});
user.setCreateTime(new Date());
// 新增user对象到数据库中,result是执行SQL影响的行数
int result = userMapper.addUser(user);
// 提交事务,否则新增(更新)数据只存在于SqlSession中,会随着程序的关闭而消失
sqlSession.commit();
System.out.println("新增了"+result+"个用户"+",该用户的id="+user.getId());	

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);  获取接口代理对象

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

在使用主键自增(例如,MySQL、SQL Server数据库)时,插入数据库后可能需要得到自增的主键值,然后使用这个值进行一些其他的操作。

新增addUser2方法,修改映射Xml文件,增加属性如下:

<insert id="addUser2" useGeneratedKeys="true" keyProperty="id">
   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})
</insert>

得到生成的主键并且赋予对象的id属性

示例: 再次运行测试类实现方法调用:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 创建一个SysUser对象
SysUser user = new SysUser();
user.setUserName("test1");
//设置user对象其他属性
// 正常情况下应该读入一张图片存到byte数组中,这里模拟字节数据
user.setHeadImg(new byte[] {1,2,3});
user.setCreateTime(new Date());
// 新增user对象到数据库中,result是执行SQL影响的行数
int result = userMapper.addUser2(user);
// 提交事务,否则新增(更新)数据只存在于SqlSession中,会随着程序的关闭而消失
sqlSession.commit();
System.out.println("新增了"+result+"个用户"+",该用户的id="+user.getId());	

addUser方法和addUser2方法接口声明一样,但是在Xml映射中,addUser2添加了useGeneratedKeys和keyProperty属性。

useGeneratedKeys会调用JDBC的getGeneratedKeys()方法取出生成的主键。  keyProperty将主键值赋予对象的id属性。

2.1.3 使用<selectKey>标签返回普通主键的值

useGeneratedKeys 用于获取自增的主键值,而有些数据库使用时并未使用自增功能,如Oracle使用序列等。

<selectKey> 标签来获取主键的值,这种方式对于是否提供主键自增功能的数据库均适用:

// 新增用户,使用selectKey方式
int addUser3(SysUser user);

 修改UserMapper.xml对应的addUser3接口方法映射:

<insert id="addUser3">
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>

2.1.4 实践练习

 

2.2 <update>标签和<delete>标签

2.2.1 <update>标签用法

在MyBatis的Mapper.xml映射文件中,定义<update>标签用于对数据进行单个或批量更新,实现步骤如下:

示例: 

1、在UserMapper接口中添加updateUser(SysUser user)方法:

UserMapper.xml中定义与之对应的SQL和配置

<update id="updateUser">
update sys_user set user_name=#{userName},user_password=#{userPassword},
user_email=#{userEmail},user_info=#{userInfo},head_img=#{headImg,jdbcType=BLOB},
create_time=#{createTime,jdbcType=TIMESTAMP} where id=#{id}
</update>

2、添加测试调用修改方法:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 获取一个SysUser对象
SysUser user = userMapper.selectById(1L);
// 修改SysUser对象信息
user.setUserName("admin2");
user.setUserEmail("admin2@mybatis.jack");
int result = userMapper.updateUser(user);
sqlSession.commit();
System.out.println("更新了"+result+"个用户信息");

2.2.2 <delete>标签用法

MyBatis的Mapper.xml中,定义<delete>标签用于对数据进行单个或批量更新。

示例: 

1、在UserMapper接口中添加deleteUserById(Long id)方法,如下

<delete id="deleteUserById">
 	delete from sys_user where id=#{id}
</delete>

2、添加测试调用删除方法:

Long userId =15L; // 欲删除用户id
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int result = userMapper.deleteUserById(userId);
sqlSession.commit();
System.out.println("删除了"+result+"个用户");

2.2.3 删除具有主从关系的主表记录

实际应用中,为了保证数据的合理性,经常会创建外键和其他表主键进行关联约束,这时当我们删除主表记录时,如有数据约束,则会报错。

解决方案是设置从表的“删除时”规则为“置为NULL”或“级联”删除。

示例: 

1、级联为例删除有角色关联的用户记录(先删除角色关联信息)

// 删除指定用户id的用户角色关联记录,返回受影响的行数

int deleteUserRolesByUserId(Long userId);

新定义一个UserRoleMapper.java接口

创建接口对应的UserRoleMapper.xml,增加删除配置,如下:

<delete id="deleteUserRolesByUserId" >
	delete from sys_user_role where user_id=#{userId}	 
</delete>

2、添加测试调用删除有角色关联用户的方法:

Long userId =16L; // 欲删除用户id
UserRoleMapper userRoleMapper = sqlSession.getMapper(UserRoleMapper.class);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 删除从表用户角色关联记录
int cnt1 = userRoleMapper.deleteUserRolesByUserId(userId);
// 删除主表用户记录
int cnt2 = userMapper.deleteUserById(userId);	
sqlSession.commit();
System.out.println("删除了"+cnt1+"条用户角色关联记录,删除了"+cnt2+"条员工记录");

2.2.4 实践练习

 

2.3 映射器方法多参数传递

2.3.1 MyBatis默认参数位置

目前案例接口中方法的参数只有一个,参数的类型可以分为两种,一种是基本类型,另一种是JavaBean。

在实际应用中经常会遇到使用多个参数的情况,可以将多个参数合并到一个JavaBean中,并使用这个JavaBean作为接口方法的参数,但是不适合于全部情况。

示例: 

1、根据用户id和角色的enabled状态获取角色列表

// 在UserMappr接口中添加根据用户id和角色enabled状态获取用户的角色
List<SysRole> selectRolesByUserIdAndRoleEnabled(Long userId, Integer enabled);
// 在UserMappr.xml中添加根据用户id和角色enabled状态获取用户的角色
<select id="selectRolesByUserIdAndRoleEnabled" resultType="SysRole">
select r.id,r.role_name,r.enabled,r.create_by,r.create_time
    from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u 
on u.id=ur.user_id where u.id=#{userId} and r.enabled=#{enabled}
</select>

2、添加测试调用查询方法: 

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<SysRole> roles = userMapper.selectRolesByUserIdAndRoleEnabled(1L, 1);
for (SysRole role : roles) {
    System.out.println("角色名:"+role.getRoleName()+",enabled:"+role.getEnabled());
}

这里运行报错,原因是无法识别多个参数

Mybatis映射器XML对于多个参数,默认情况下只识别arg0、arg1、paraml和param2这种内部定义的名称,

所以将参数名定义为#{arg0}和#{arg1}或者#{param1}和#{param2}即可解决错误,如下:

<select id="selectRolesByUserIdAndRoleEnabled" resultType="SysRole">
select r.id,r.role_name,r.enabled,r.create_by,r.create_time  from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u on u.id=ur.user_id where u.id=#{param1} and r.enabled=#{param2}
</select>

u.id=#{param1} and r.enabled=#{param2}  这里参数名换成mybatis内部定义的

2.3.2 使用Map类型作封装参数

 Map是键+值对形式数据格式集合,也可以解决多参数问题,通过key来映射Mapper.xml中SQL使用的参数名字,value用来存放参数值,需要多个参数时,通过Map的key-value方式来传递参数值,如下:

示例:

1、根据用户id和角色的状态(enabled字段)获取角色列表

将多个参数以Map形式封装传递

List<SysRole> selectRolesByUserIdAndRoleEnabledByMap(Map<String,Object> params);

Mybatis能够识别map中的key

<select id="selectRolesByUserIdAndRoleEnabledByMap" resultType="SysRole">
select r.id,r.role_name,r.enabled,r.create_by,r.create_time
    from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u 
on u.id=ur.user_id where u.id=#{userId} and r.enabled=#{enabled}
</select>

2、添加测试调用map传递参数的查询:

	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	Map<String, Object> paramsMap = new HashMap<String, Object>();
	paramsMap.put("userId", 1L);
	paramsMap.put("enabled", 1);
	List<SysRole> roles = userMapper.selectRolesByUserIdAndRoleEnabledByMap(paramsMap);	
	for (SysRole role : roles) {
		System.out.println("角色名:"+role.getRoleName()+",enabled:"+role.getEnabled());
	}

创建Map对象,将传递的参数进行封装

传入map对象进行方法调用

2.3.3 使用注解类型作为参数

MyBatis还提供了对Mapper接口方法多个参数进行注解说明

参数前使用@Param(“参数名”)进行修饰:

示例:

1、根据用户id和角色的enabled状态获取角色列表

使用@Param注解进行参数名修饰说明

List<SysRole> selectRolesByUserIdAndRoleEnabledByAnnotation(@Param("userId")Long userId,
			@Param("enabled")Integer enabled);

直接对应@Param修饰后的名称即可

<select id=" selectRolesByUserIdAndRoleEnabledByAnnotation" resultType="SysRole">
select r.id,r.role_name,r.enabled,r.create_by,r.create_time
    from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u 
on u.id=ur.user_id where u.id=#{userId} and r.enabled=#{enabled}
</select>

如果映射器中的方法定义有多个参数,可以通过Map的key-value方式传递参数值来解决,但由于这种方式还需要自己手动创建Map以及对参数进行赋值,使用起来并不简洁,所以推荐使用@Param注解的方式来传递映射器中方法的多参数。

2.3.4 实践练习

 

2.4 MyBatis注解映射

2.4.1 MyBatis注解的基本用法

为了提高开发效率,MyBatis提供了另外一种注解的方式来实现接口方法的映射。

MyBatis注解方式就是将SQL语句直接写在接口方法上,常用包含@Select、@Insert、@Update、@Delete和@Provider五种,分别对应CRUD操作。

@Select(“select * from 用户表名”)
public List<User> selectUsrs();

对于需求比较简单的系统,其效率较高。缺点是当SQL有变化时,需要重新编译代码。一般情况下不建议使用注解方式

 @Select注解用于查询数据

示例:

1、在RoleMapper中实现根据角色id查询角色信息对象

@Select("select id, role_name roleName, enabled, create_by createBy, "+ 
"create_time createTime from sys_role where id =#{id}")
SysRole selectRoleById1(Long roleId);

就是将以前写在Xml中的配置拿到了接口中

@Select注解查询时,默认情况下需要保证表中的列和实体中的属性名一致,如果存在表中下划线,而类中是驼峰命名时可以通过以下方式解决:

1、在主配置中开启驼峰命名设置

2、在@Select注解时使用 @Results注解进行说明,类似resultMap标签

@Results({
@Result(property="id",column="id",id=true),
			@Result(property="roleName",column="role_name"),
			@Result(property="enabled",column="enabled"),
			@Result(property="createBy",column="create_by"),
			@Result(property="createTime",column="create_time")
})
@Select("select id, role_name, enabled, create_by, create_time "
			+ "from sys_role where id =#{id}")
SysRole selectRoleById2(Long roleId);

2.4.2 @Insert注解

 @Insert注解用于新增数据

示例:

1、在RoleMapper中实现新增角色信息

@Insert("insert into sys_role(id,role_name,enabled,create_by,create_time) "
		+ "values(#{id},#{roleName},#{enabled},#{createBy},"
		+ "#{createTime,jdbcType=TIMESTAMP})")
int addRole(SysRole role);

就是将以前写在Xml中的sql配置拿到了接口中

2、在RoleMapper中实现新增角色信息,并且获取自增主键值

@Insert("insert into sys_role(role_name,enabled,create_by,create_time) "
	+ "values(#{roleName},#{enabled},#{createBy},"
	+ "#{createTime,jdbcType=TIMESTAMP})")
@Options(useGeneratedKeys=true, keyProperty="id")
int addRole2(SysRole role);

声明获取返回自增主键值,放入id属性中

2.4.3 @Update注解

 @Update注解用于修改数据

示例:

1、使用注解修改角色信息,接收角色对象,返回影响行数

@Update("update sys_role set role_name=#{roleName}, enabled=#{enabled}, "
    + "create_by=#{createBy}, create_time=#{createTime,jdbcType=TIMESTAMP}  where id=#{id}")
int updateRole2(SysRole role);

2.4.4 @Delete注解

 @Delete注解用于删除数据

示例:

1、使用注解删除角色信息

@Delete("delete from sys_role where id=#{id}")
int deleteRoleById2(Long id);

2.4.5 @Provider注解

 当SQL语句需要添加条件或过于复杂时,普通CRUD注解无法满足,需要使用Provider注解应对复杂的SQL处理,包括了以下几种:

@SelectProvider

@InsertProvider

@UpdateProvider

@DeleteProvider

几种注解用法一致,主要用于配合对应注解产生复杂的Sql语句时使用

示例:

使用@SelectProvider实现权限信息复杂查询

public interface PrivilegeMapper {
	…
	@SelectProvider(type=PrivilegeProvider.class, method="selectPrivilegeById2")
	SysPrivilege selectPrivilegeById2(Long id);
}
public class PrivilegeProvider {
public String selectPrivilegeById2(final Long id) {
		return new SQL() {
			{
				SELECT("id, privilege_name, privilege_url");
				FROM("sys_privilege");
				WHERE("id=#{id}");			
			}
		}.toString();
	}
}

2.4.4 实践练习

 

总结:

  • MyBatis数据库操作时,需要先建立一个操作接口,声明操作的抽象方法,然后针对接口建立Mapper.xml映射文件,使用<insert><update><delete><select>标签分别完成对应方法Sql语句和参数、返回结果的配置。
  • <insert>标签完成增加映射时,可以使用useGeneratedKeys、keyProperty获取主键自增产生的值,也可以使用<selectKey>的方式获取。
  • 接口中方法如果接收多个参数时,可以采用默认参数名匹配,或者使用Map对参数进行封装,也可以使用@Param注解对参数进行修饰。
  • 对于简单的系统操作,可以直接在接口方法上使用@Select、@Insert、@Update、@Delete注解完成Sql语句匹配,提高开发效率。

 

上一篇:Java快速入门


下一篇:队列顺序存储3