mybatis的xml映射器
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
xml的基本映射标签
1.select标签
mapper 接口中的方法:
/**
* 查询所有
*/
List<User> selectList();
mapper xml的映射
<select id="selectList" resultType="cn.hk.bean.User">
select * from t_user
</select>
测试代码:
@Test
public void testSelectList(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用查询方法
mapper.selectList();
//关闭资源
SqlSessionUtils.close(sqlSession);
}
2.insert 标签
mapper 接口中的方法:
/**
* 查询所有
*/
List<User> selectList();
mapper xml的映射
<select id="selectList" resultType="cn.hk.bean.User">
select * from t_user
</select>
测试代码:
@Test
public void testInsert(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值
User u = new User();
u.setName("王语嫣");
u.setPhone("1234");
u.setPwd("abc");
System.out.println(u);
int i = mapper.insertUser(u);
System.out.println(u);
//提交事务
sqlSession.commit();
//关闭资源
SqlSessionUtils.close(sqlSession);
}
插入日志查看:
User{id=null, name='王语嫣', pwd='abc', phone='1234'}
DEBUG [main] - ==> Preparing: insert into t_user(name ,pwd,phone) values(?,?,?)
DEBUG [main] - ==> Parameters: 王语嫣(String), abc(String), 1234(String)
DEBUG [main] - <== Updates: 1
User{id=6, name='王语嫣', pwd='abc', phone='1234'}
keyProperty="id" keyColumn="id" useGeneratedKeys="true" 配置了可以把 插入的数据的自增id
返回给对象
3.update 标签
mapper 接口中的方法:
/**
* 修改user
*/
int updateUser(User u);
mapper xml的映射
<update id="updateUser" parameterType="cn.hk.bean.User">
update t_user set
name = #{name},
pwd = #{pwd},
phone = #{phone}
where id = #{id}
</update>
测试代码:
@Test
public void testUpdate(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值
User u = new User();
u.setId(3);
u.setName("周芷若");
u.setPhone("1234");
u.setPwd("abc");
System.out.println(u);
int i = mapper.updateUser(u);
System.out.println(u);
//提交事务
sqlSession.commit();
//关闭资源
SqlSessionUtils.close(sqlSession);
}
4.delete标签
mapper 接口中的方法:
/**
* 通过id删除
*/
int deleteUser(Integer id);
mapper xml的映射
<delete id="deleteUser">
delete from t_user where id = #{id}
</delete>
测试代码:
@Test
public void testDelete(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值
int i = mapper.deleteUser(2);
System.out.println(i);
//提交事务
sqlSession.commit();
//关闭资源
SqlSessionUtils.close(sqlSession);
}
5.注意事项
-
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中
-
mybatis的默认手动提交事务,进行更新操作(insert,update,delete) 操作后 一定要提交事务 commit()
6.参数
-
之前见到的所有语句都使用了简单的参数形式。但实际上,参数是 MyBatis 非常强大的元素。对于大多数简单的使用场景,你都不需要使用复杂的参数,比如:
-
一个参数
<select id="selectUsers" resultType="User"> select id, name, pwd from t_user where id = #{id} </select>
上面的这个示例说明了一个非常简单的命名参数映射。鉴于参数类型(parameterType)会被自动设置为
int
,这个参数可以随意命名。原始类型或简单数据类型(比如Integer
和String
)因为没有其它属性,会用它们的值来作为参数。<insert id="insertUser" parameterType="User"> insert into t_user (name, pwd,phone) values (#{name}, #{pwd}, #{phone}) </insert>
如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。
对传递语句参数来说,这种方式真是干脆利落。不过参数映射的功能远不止于此。
和 MyBatis 的其它部分一样,参数也可以指定一个特殊的数据类型。
#{id,javaType=int,jdbcType=NUMERIC}
对于数值类型,还可以设置 numericScale 指定小数点后保留的位数。 #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
尽管上面这些选项很强大,但大多时候,你只须简单指定属性名,顶多要为可能为空的列指定
jdbcType
,其他的事情交给 MyBatis 自己去推断就行了。#{name,jdbcType=VARCHAR}
7.字符串替换
默认情况下,使用 #{}
参数语法时,MyBatis 会创建 PreparedStatement
参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。
#{} 参数占位符
<select id="selectByName" parameterType="string" resultType="cn.hk.bean.User">
select * from t_user where name = #{name}
</select>
测试日志:
DEBUG [main] - ==> Preparing: select * from t_user where name = ? //sql的占位符
DEBUG [main] - ==> Parameters: 张三(String)
TRACE [main] - <== Columns: id, name, pwd, phone
TRACE [main] - <== Row: 1, 张三, 123456, 123456
DEBUG [main] - <== Total: 1
User{id=1, name='张三', pwd='123456', phone='123456'}
${} 参数拼接
<select id="selectByName" parameterType="string" resultType="cn.hk.bean.User">
select * from t_user where name = ${name}
</select>
测试代码:
public void testSelectName(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值 参数设置注意加:''
User user = mapper.selectByName("'张三'");
System.out.println(user);
//关闭资源
SqlSessionUtils.close(sqlSession);
}
测试日志:
DEBUG [main] - ==> Preparing: select * from t_user where name = '张三'
// sql的字符串拼接
DEBUG [main] - ==> Parameters:
TRACE [main] - <== Columns: id, name, pwd, phone
TRACE [main] - <== Row: 1, 张三, 123456, 123456
DEBUG [main] - <== Total: 1
User{id=1, name='张三', pwd='123456', phone='123456'}
提示 ${} 用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击
8. 结果映射
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap
能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
之前你已经见过简单映射语句的示例,它们没有显式指定 resultMap
。
在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap
,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上会发生什么?
javaBean:
public class User {
private Integer id;
private String name;
private String pwd;
private String phone;
}
xml的映射:
<select id="selectByPrimaryKey" parameterType="integer" resultType="cn.hk.bean.User">
select id u_id,name u_name,pwd u_password,phone u_phone from t_user where id = #{id}
</select>
类名和属性名不能匹配
测试结果:
@Test
public void testSelectOne(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值
User user = mapper.selectByPrimaryKey(4);
System.out.println(user);
//关闭资源
SqlSessionUtils.close(sqlSession);
}
查看日志:
DEBUG [main] - ==> Preparing: select id u_id,name u_name,pwd u_password,phone u_phone from t_user where id = ?
DEBUG [main] - ==> Parameters: 4(Integer)
TRACE [main] - <== Columns: u_id, u_name, u_password, u_phone
TRACE [main] - <== Row: 4, 郭靖, aaa, 1234
DEBUG [main] - <== Total: 1
null
Columns 和 resultType 不匹配
使用resultMap是解决列名不匹配的一种方式
<!--
resultMap 结果映射
id 当前命名空间中的一个唯一标识,用于标识一个结果映射。
type 类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。
<id property="id" column="u_id"/>
<result property="name" column="u_name"/>
id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。
id 元素对应的属性会被标记为对象的标识符
property 映射到列结果的字段或属性。
column 数据库中的列名,或者是列的别名(和传递给 resultSet.getString(columnName) 方法的参数一样。)
javaType 一个 Java 类的全限定名,或一个类型别名
jdbcType JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。
注意类型 VARCHAR 大写
-->
<resultMap id="rs_map" type="cn.hk.bean.User">
<id property="id" column="u_id"/>
<result property="name" javaType="string" column="u_name" jdbcType="VARCHAR"/>
<result property="pwd" column="u_password"/>
<result property="phone" column="u_phone"/>
</resultMap>
<select id="selectByPrimaryKey" parameterType="integer" resultMap="rs_map">
select id u_id,name u_name,pwd u_password,phone u_phone from t_user where id = #{id}
</select>
测试代码:
@Test
public void testSelectOne(){
// 获取SqlSession
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
// 通过session获取Mapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 传入参数返回值
User user = mapper.selectByPrimaryKey(4);
System.out.println(user);
//关闭资源
SqlSessionUtils.close(sqlSession);
}
测试日志:
DEBUG [main] - ==> Preparing: select id u_id,name u_name,pwd u_password,phone u_phone from t_user where id = ?
DEBUG [main] - ==> Parameters: 4(Integer)
TRACE [main] - <== Columns: u_id, u_name, u_password, u_phone
TRACE [main] - <== Row: 4, 郭靖, aaa, 1234
DEBUG [main] - <== Total: 1
User{id=4, name='郭靖', pwd='aaa', phone='1234'}
9 mybatis的注解开发:
映射器注解
设计初期的 MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,映射语句也是定义在 XML 中的。而在 MyBatis 3 中,我们提供了其它的配置方式。MyBatis 3 构建在全面且强大的基于 Java 语言的配置 API 之上。它是 XML 和注解配置的基础。注解提供了一种简单且低成本的方式来实现简单的映射语句。
提示 不幸的是,Java 注解的表达能力和灵活性十分有限。尽管我们花了很多时间在调查、设计和试验上,但最强大的 MyBatis 映射并不能用注解来构建——我们真没开玩笑。
常用的注解如下:
@Select 查询数据注解
@Insert 插入数据注解
@Delete 删除数据注解
@Update 修改数据注解
@Options 选项配置
@Results 手动映射配置
@Result: @results中的具体的某一列的映射信息配置
在列和属性或字段之间的单个结果映射。属性:id、column、javaType、jdbcType、typeHandler、one、many。id 属性和 XML 元素 <id> 相似,它是一个布尔值,表示该属性是否用于唯一标识和比较对象。one 属性是一个关联,和 <association> 类似,而 many 属性则是集合关联,和 <collection> 类似。这样命名是为了避免产生名称冲突。
注解的案例:
public interface UserMapperAnnotation {
@Select(" select id u_id,name u_name,pwd u_password,phone u_phone from t_user where id = #{id}")
@Results({
@Result(id = true,property = "id",column = "u_id"),
@Result(property = "name",column = "u_name"),
@Result(property = "pwd",column = "u_password"),
@Result(property = "phone",column = "u_phone"),
})
User selectByPrimaryKey(Integer id);
@Select("select * from t_user")
List<User> selectList();
@Insert("insert into t_user(name,pwd,phone) values(#{name},#{pwd},#{phone})")
@Options(
keyProperty ="id",
keyColumn = "id",
useGeneratedKeys = true
)
int insertUser(User u);
@Delete("delete from t_user where id = #{id}")
int deleteUserById(Integer id);
@Update("update t_user set name = #{name},pwd=#{pwd},phone = #{phone} where id = #{id}")
int updateUser(User u);
}
注意: 需要在config中配置mapper接口:
<!-- 配置mapper的映射-->
<mappers>
<mapper class="cn.hk.mapper.UserMapperAnnotation"></mapper>
</mappers>
测试代码:
package cn.hk.test;
import cn.hk.bean.User;
import cn.hk.mapper.UserMapperAnnotation;
import cn.hk.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
/**
* @author 黄药师
* @date 2020-05-11 16:16
* @desc
*/
public class UserAnnotationTest {
@Test
public void testSelectOne(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
User user = mapper.selectByPrimaryKey(1);
System.out.println(user);
SqlSessionUtils.close(sqlSession);
}
@Test
public void testSelectList(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
List<User> users = mapper.selectList();
System.out.println(users);
SqlSessionUtils.close(sqlSession);
}
@Test
public void testInsert(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
User user = new User();
user.setPhone("1111");
user.setPwd("1234");
user.setName("黄蓉");
System.out.println(user);
int i = mapper.insertUser(user);
System.out.println(i);
//提交事务
sqlSession.commit();
System.out.println(user);
// 关闭资源
SqlSessionUtils.close(sqlSession);
}
@Test
public void testDelete(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
int i = mapper.deleteUserById(3);
System.out.println(i);
//提交事务
sqlSession.commit();
// 关闭资源
SqlSessionUtils.close(sqlSession);
}
@Test
public void testUpdate(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
User user = new User();
user.setPhone("1111");
user.setPwd("1234");
user.setName("周伯通");
user.setId(1);
int i = mapper.updateUser(user);
System.out.println(i);
//提交事务
sqlSession.commit();
// 关闭资源
SqlSessionUtils.close(sqlSession);
}
}
10 多参数的处理
传递多个参数给一个映射器方法。在多个参数的情况下,默认它们将会以 param 加上它们在参数列表中的位置来命名,比如:#{param1}、#{param2}等。如果你想(在有多个参数时)自定义参数的名称,那么你可以在参数上使用 @Param(“paramName”) 注解。
如果你的映射方法接受多个参数,就可以使用这个注解自定义每个参数的名字。否则在默认情况下,除 RowBounds
以外的参数会以 “param” 加参数位置被命名。例如 #{param1}
, #{param2}
。如果使用了 @Param("person")
,参数就会被命名为 #{person}
。
-
多个参数的使用
不使用注解的多参数xml映射: /** * 查询 多个参数 * @return */ User selectUser(String name,String pwd); <select id="selectUser" resultType="cn.hk.bean.User"> select * from t_user where name = #{param1} and pwd = #{param2} </select> 使用注解的多参数设置: User selectUser01(@Param("username") String name,@Param("password") String pwd); <select id="selectUser01" resultType="cn.hk.bean.User"> select * from t_user where name = #{username} and pwd = #{password} </select>
-
把多个参数封装成一个map
User selectUser02(Map<String,Object> map); <!-- #{map的key的名称} --> <select id="selectUser02" parameterType="map" resultType="cn.hk.bean.User"> select * from t_user where name = #{name} and pwd = #{pwd} </select>
测试代码:
@Test public void testSelectUser02(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap<>(); map.put("name","王语嫣"); map.put("pwd","abc"); User user = mapper.selectUser02(map); System.out.println(user); }
-
把多个参数封装成对象
User selectUser03(User user); <!-- #{bean的属性的名称} --> <select id="selectUser03" parameterType="cn.hk.bean.User" resultType="cn.hk.bean.User"> select * from t_user where name = #{name} and pwd = #{pwd} </select>
测试代码:
@Test public void testSelectUser03(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setName("王语嫣"); user.setPwd("abc"); User u = mapper.selectUser03(user); System.out.println(u); SqlSessionUtils.close(sqlSession); }