第一章已经使用mybatis的核心对象sqlsession做了一个crud
我们仔细看一下执行sql语句的方法代码
int i = session.insert("com.wh.mapper.UserMapper.addUser", user);
List<User> list =session.selectList("com.wh.mapper.UserMapper.selAllUser");
int i = session.update("com.wh.mapper.UserMapper.upUser",user);
在参数里写sql位置时好像很麻烦,例如com.wh.mapper.UserMapper.addUser,一不小心就会写错,找不到sql语句导致报错。而且代码耦合性很强,mapper文件名发生改变,就要去修改java代码
可不可以有一种约定? 让这个sql位置的命名不让人任意起名,而是按照约定指定好,mybatis就可以自动找到这个sql语句。
那么如果有了这种约定,掉crud方法还需要程序员来写吗?
已经通过约定将sql语句的位置告诉mybatis了,mybatis不就可以自动找到sql,执行sql,做crud了吗
于是mybatis便有了mybatis动态代理
mybatis对mapper的命名有以下约束
(1) Namespace 的值是接口的完全限定名
(2) 标签中的id描述的是接口中的方法,id必须是接口中的方法
(3) parameterType一定接口中方法的参数类型要一致。
通过这三点,mybaits就可以自动生成接口的实现类对象了
正文开始
动态代理开发步骤
准备好实体类
public class Person {
private Integer id;
private String name;
private String gender;
private Integer age;
private Date birthday;
// ...省略
}
1. 创建接口
public interface PersonMapper {
void addPerson(Person person);
Person selPersonById(int id);
List<Person> selAllPerson();
void delPersonById(int id);
void upPersonById(Person person);
}
2.创建映射文件
<mapper namespace="com.wh.mapper.PersonMapper">
<insert id="addPerson" parameterType="Person">
insert into person (name,gender,age,birthday) values (#{name},#{gender},#{age},#{birthday})
</insert>
<select id="selPersonById" parameterType="int" resultType="Person">
select id,name,gender,age,birthday from person where id = #{id}
</select>
<select id="selAllPerson" resultType="Person">
select id,name,gender,age,birthday from person
</select>
<delete id="delPersonById" parameterType="int">
delete from person where id = #{id}
</delete>
<update id="upPersonById" parameterType="Person">
update person set name = #{name}, gender = #{gender}, age = #{age}, birthday = #{birthday} where id = #{id}
</update>
</mapper>
3. 获取mybatis的代理对象
session.getMapper(PersonMapper.class);
**getMapper()**就是获取实现接口的代理类对象,该对象封装的操作就是
第一章中sqlsession的crud案例代码,只不过sql语句的位置已经按照约定命名,mybatis可以自动找到,参数不用程序员在写了。
4.测试
public class PersonMapperTest {
@Test
public void testadd(){
SqlSession session = SessionUtils.getSqlSession();
// debug查看源码创建代理对象原理
PersonMapper personMapper = session.getMapper(PersonMapper.class);
Person person = new Person();
person.setName("华仔");
person.setGender("男");
person.setAge(18);
person.setBirthday(new Date());
// debug查看执行操作原理
personMapper.addPerson(person);
session.commit();
session.close();
}
@Test
public void testdel(){
SqlSession session = SessionUtils.getSqlSession();
PersonMapper personMapper = session.getMapper(PersonMapper.class);
personMapper.delPersonById(7);
session.commit();
session.close();
}
@Test
public void testup(){
SqlSession session = SessionUtils.getSqlSession();
PersonMapper personMapper = session.getMapper(PersonMapper.class);
Person person = new Person();
person.setId(8);
person.setName("华仔");
person.setGender("男");
person.setAge(18);
person.setBirthday(new Date());
personMapper.upPersonById(person);
session.commit();
session.close();
}
@Test
public void testsel(){
SqlSession session = SessionUtils.getSqlSession();
PersonMapper personMapper = session.getMapper(PersonMapper.class);
Person person = personMapper.selPersonById(2);
System.out.println(person);
session.commit();
session.close();
}
@Test
public void testselAll(){
SqlSession session = SessionUtils.getSqlSession();
PersonMapper personMapper = session.getMapper(PersonMapper.class);
List<Person> personList = personMapper.selAllPerson();
for (Person person : personList) {
System.out.println(person);
}
session.commit();
session.close();
}
回忆一下第一章中的
sqlSession.insert()
sqlSession.delete()
sqlSession.update()
sqlSession.select()
这些crud方法,都是有程序员代码手动调用的
其实动态代理的原理就是
按照约定,只要接口名和方法名确定,就能找到sql。
mybatis在要实现的接口方法里自动调用执行了sqlSession.XXX();
两个底层原理
只提一下,想要搞懂原理可以在网上找一下。。。
1.代理对象是如何生成的?用的什么代理技术?
代理技术我了解的有jdk动态代理和cglib,这种实现接口的应该是jdk动态代理吧,可以找一下专门分析原理的文章。
想查看代理对象生成机制可以在session.getMapper()方法打上断点,bebug一下查看代理对象生成的过程
2.如何调用方法执行的sql
personMapper.addPerson(person);
可以在这中执行sql的方法上打个断点,debug一下查看执行过程
根据我的观察,是用的反射技术调用的方法
这两个底层原理,想了解可以找一下专门分析的文章
附上一篇我看到的比较好的分析原理的文章
https://www.cnblogs.com/hopeofthevillage/p/11384848.html