Mybatis动态代理与传参

Mybatis动态代理实现CURD

步骤

去掉Dao接口的实现类

getMapper获取代理对象

只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao 接口类的 class 值。(反射原理)

1
2
3
4
5
6
SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);

//使用工具类获取session
StudentDao studentDao =
MyBatisUtil.getSqlSession().getMapper(StudentDao.class);

使用Dao代理对象方法执行SQL语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//s所有的方法必须都在StudentDao接口中有所定义
//select 方法:
@Test
public void testSelect() throws IOException {
final List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}

//insert 方法:
@Test
public void testInsert() throws IOException {
Student student = new Student();
student.setId(1006);
student.setName("林浩");
student.setEmail("linhao@163.com");
student.setAge(26);
int nums = studentDao.insertStudent(student);
System.out.println("使用 Dao 添加数据:"+nums);
}

//update 方法
@Test
public void testUpdate() throws IOException {
Student student = new Student();
student.setId(1006);
student.setAge(28);
int nums = studentDao.updateStudent(student);
System.out.println("使用 Dao 修改数据:"+nums);
}
//delete 方法
@Test
public void testDelete() throws IOException {
int nums = studentDao.deleteStudent(1006);
System.out.println("使用 Dao 修改数据:"+nums);
}

基于动态代理的原理分析

MapperProxy类定义

invoke方法

重点方法

深入理解参数

parameterType

parameterType: 接口中方法参数的类型, 值是类型的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到 mapper 文件的 sql 语句。

支持传入参数的类型与别名映射如表所示:

Mybatis传递参数

一个简单参数

Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。

接口方法

1
Student selectById(int id);

mapper文件

1
2
3
4
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
#{studentId} , studentId 是自定义的变量名称,和方法参数名无关。#表示占位符

测试方法

1
2
3
4
5
6
@Test
public void testSelectById(){
//传入了一个参数
Student student = studentDao.selectById(1005);
System.out.println("查询 id 是 1005 的学生:"+student);
}

多个参数

使用@Param

当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。

  • 接口方法:
1
List selectMultiParam(@Param("personName") String name, @Param("personAge") int age); 
  • mapper 文件:

    1
    2
    select id,name,email,age from student where name=#{personName} or age =#{personAge}

    1
    2
    3
    4
    @Test 
    public void testSelectMultiParam(){
    List stuList = studentDao.selectMultiParam("李力",20); stuList.forEach( stu -> System.out.println(stu));
    }

多个参数–适用对象

使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。 语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 } javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }

创建保存参数值的对象QueryParam

1
2
3
4
5
6
package com.bjpowernode.vo;
public class QueryParam {
private String queryName;
private int queryAge;
//set ,get 方法
}

接口方法

1
List<Student> selectMultiObject(QueryParam queryParam);

mapper文件—-必须保证和对象的属性名相同

1
2
3
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{queryName} or age=#{queryAge}
</select

或者

1
2
3
4
5
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name=#{queryName,javaType=string,jdbcType=VARCHAR}
or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>

测试方法

1
2
3
4
5
6
7
8
@Test
public void selectMultiObject(){
QueryParam qp = new QueryParam();
qp.setQueryName("李力");
qp.setQueryAge(20);
List<Student> stuList = studentDao.selectMultiObject(qp);
stuList.forEach( stu -> System.out.println(stu));
}

多个参数–按照位置

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1} 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式>。

接口方法

1
List<Student> selectByNameAndAge(String name,int age);

mapper文件

1
2
3
<select id="selectByNameAndAge" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>

测试方法

1
2
3
4
5
6
@Test
public void testSelectByNameAndAge(){
//按位置参数
List<Student> stuList = studentDao.selectByNameAndAge("李力",20);
stuList.forEach( stu -> System.out.println(stu));
}

多个参数–使用Map

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key, Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。

接口方法

1
List<Student> selectMultiMap(Map<String,Object> map);

mapper文件

1
2
3
4
<select id="selectMultiMap" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>
//通过key来传递参数

测试方法

1
2
3
4
5
6
7
8
9
@Test
public void testSelectMultiMap(){
Map<String,Object> data = new HashMap<>();
data.put("myname","李力");// #{myname}
data.put("myage",20); // #{myage}
List<Student> stuList = studentDao.selectMultiMap(data);
stuList.forEach( stu -> System.out.println(stu));
}
//存储参数的类型是Object

占位符#和$

#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法,

mapper文件

1
2
3
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>

转换为Mybatis的执行是:

1
2
3
String sql=select id,name,email,age from student where id=?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);

$

$ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作。

因为存在拼接的操作,所以可能会存在SQL注入的安全隐患

谢谢你的支持哦,继续加油.