在前面的例子中自定义Dao接口实现类的时候发现这样一个问题:Dao接口的实现类其实并没用干什么实质性的工作,它仅仅就是通过SqlSession的相关API定位到映射文件mapper中 相应的id的sql语句中,真正对DB进行操作的是由框架通过mapper中的SQL完成的。
所以,Mybatis框架就抛开了Dao的实现类,直接定位到映射文件mapper中的相应SQL语句,对DB进行操作。这种对Dao的实现方式称为Mapper的动态代理方式。
mapper动态代理不需要程序员实现Dao接口。接口是由Mybatis结合映射文件自动生成的动态代理实现的。
接下来,我们在实现基本的增删改查的操作的项目的基础之上进行修改。
1、映射文件mapper的namespace属性值
一般情况下,一个Dao接口的实现类方法使用的是同一个SQL映射文件中的SQL映射id,所以,Mybatis框架要求,将映射文件中<mapper/>标签的namespace属性舌吻DAO接口的全类名,则系统会根据方法所属Dao接口,自动到相应的namespace的映射文件中查找相应的SQL映射。
也就是说,当我们设置了namespace之后,可以通过接口名就可以定位到mapper中的方法
2、修改日志输出控制文件
##define an appender named console
log4j.appender.console=org.apache.log4j.ConsoleAppender
#The Target value is System.out or System.err
log4j.appender.console.Target=System.out
#set the layout type of the apperder
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#set the layout format pattern
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
##define a logger
##.test is mybatis.xml namespace
# 这里修改路径
log4j.logger.com.test.dao.IStudentDao=debug,console
3、Dao接口方法名字
public interface IStudentDao {
//对一个表的基本操作
void deleteStuById(int id);
void insertStudent(Student student);
//插入之后,这个插入的对象就能得到id。
void insertStuCacheId(Student student);
void updateStu(Student student);
List<Student> selectAllStudent();
//map使用很少
Map<String, Object> selectAllStudentMap();
Student selectStudentById(int id);
List<Student> selectStuByName(String name);
}
4、mapper映射文件不变
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.dao.IStudentDao">
<!-- parameterType已经定义了别名 -->
<insert id="insertStudent" >
insert into student(name,age,score) values(#{name},#{age},#{score})
</insert>
<insert id="insertStuCacheId" >
insert into student(name,age,score) values(#{name},#{age},#{score})
<!-- order:指定id的生成与插入语句的顺序关系 -->
<selectKey resultType="int" keyProperty="id" order="AFTER">
<!-- 这里有两种方式可以选择 -->
<!-- 1、select last_insert_id() -->
<!-- 2、select @@identity -->
select @@identity
</selectKey>
</insert>
<!-- id里面的内容是接口里面的方法名 ,提供给别人使用-->
<delete id="deleteStuById">
delete from student where id=#{xxx}
</delete>
<update id="updateStu">
update student set name=#{name},age=#{age},score=#{score} where id=#{id}
</update>
<select id="selectAllStudents" resultType="com.test.beans.Student">
select * from student
</select>
<select id="selectStudentById" resultType="com.test.beans.Student">
select * from student where id=#{id}
</select>
<select id="selectStuByName" resultType="com.test.beans.Student">
<!-- 这种查询方式表示只要含有xxx都会被查询到 -->
<!-- 下面这种方式推荐使用,可以方式sql注入。动态参数 -->
select * from student where name like '%' #{xxx} '%'
<!-- select * from student where name like concat('%',#{xxx},'%')-->
<!-- 下面这种情况表示纯粹的字符串拼接,在输出结果里面没有参数显示:这种情况不建议使用 -->
<!-- select * from student where name like '%${value}%'-->
</select>
</mapper>
5、Dao对象的获取
使用时候,只需调用SqlSession的getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定Dao接口类的class值。
下面给出全部的测试类代码:
public class MyTest {
private IStudentDao dao ;
private SqlSession sqlSession;
@Before
public void testBefore(){
sqlSession = MybatisUtil.getSqlSession();
dao = sqlSession.getMapper(IStudentDao.class);
}
@After
public void after(){
if(sqlSession!=null){
sqlSession.close();
}
}
@Test
public void testinsertStu(){
Student student = new Student("张三",23,93.5);
dao.insertStudent(student);
sqlSession.commit();
}
@Test
public void testinsertStuCacheId(){
Student student = new Student("冯冬冬",20,97.5);
System.out.println("插入之前的id:"+student);
dao.insertStuCacheId(student);
sqlSession.commit();
System.out.println("插入之后的id:"+student.getId());
}
@Test
public void testDelete(){
dao.deleteStuById(30);
sqlSession.commit();
}
@Test
public void testUpdate(){
Student student = new Student("王胜男1",19,96.5);
student.setId(22);
dao.updateStu(student);
sqlSession.commit();
}
//选出数据库中所有的对象
@Test
public void testselectAllStudent() {
System.out.println("===========");
List<Student> students = dao.selectAllStudent();
for (Student student : students) {
System.out.println(student);
}
}
//根据id号选出学生
@Test
public void testselectStudentById() {
Student student = dao.selectStudentById(24);
System.out.println(student);
}
@Test
public void testselectStuByName() {
List<Student> students = dao.selectStuByName("冯");
for (Student student : students) {
System.out.println(student);
}
}
// 需要删除掉这个测试2
// @Test
// public void testselectAllStudentMap() {
// Map<String, Object> map=dao.selectAllStudentMap();
// System.out.println(map.get("冯冬冬"));
// }
}
6、删除Dao的实现类
因为在这里到dao获取了IStudentDao的代理,Mybatis会自动映射接口和mapper,所以接口的实现类不再需要。
dao = sqlSession.getMapper(IStudentDao.class);
下面我们可以看到,Dao实现对象是由JDK的Proxy动态代理自动生成的
注意:我们在测试时候需要删除selectAllStudentMap,因为在这个测试条件下面会出错,也就是下面的代码。
@Test
public void testselectAllStudentMap() {
Map<String, Object> map=dao.selectAllStudentMap();
System.out.println(map.get("冯冬冬"));
}