原始dao和Mapper动态代理的开放方式---Mybatis学习笔记(六)

1.原始Dao开发方式

原始Dao开发方法需要程序员编写Dao接口和Dao实现类。 
1.映射文件:(user.xml)

<?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">
<!-- namespace :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。 -->
<mapper namespace="test">

<!-- 根据Id获取用户信息 ,返回一条数据-->
<!-- 通过<select>进行数据库查询
id:标识映射文件中的sql
将sql语句封装到mappedStatement对象中,所以将id称为statement的id
parameterType:指定输入参数的类型
#{}:表示一个占位符
#{id}:其中的id表示接收输入的参数,参数的名称就是id,如果输入参数为简单类型,#{}中的参数名可以任意,可以value也可以其它名称。
resultType:指定sql输出结果的所映射的java对象类型。select指定resultType表示将单条记录映射成的java对象。
 -->
<select id="findUserById" parameterType="int" resultType="com.huihui.pojo.User">
    select * from user where id=#{id}
</select>
<!-- 自定义条件查询用户列表,可能返回多条 -->
<!-- 
${}:表示拼接sql串,将接收到的参数的内容不加任何修饰拼接到sql中。
使用${}拼接sql,可能引起sql注入
${value}:接收输入参数的内容,如果传入的类型是简单类型,${}中只能使用value
 -->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="com.huihui.pojo.User">
    select * from user where username like '%${value}%'
</select>

<!-- 添加用户 -->
<!-- 
parameterType:指定输入参数类型为pojo
#{}中指定pojo的属性名,接收到pojo对象的属性值
 -->
<insert id="insertUser" parameterType="com.huihui.pojo.User" >
    insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
    <!-- selectKey将主键返回,需要再返回 -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        select LAST_INSERT_ID()
    </selectKey>
</insert>

<!-- 删除用户 -->
<!-- 根据id删除用户,需要输入id值 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
    delete from user where id = #{id}
</delete>

<!-- 更新用户 -->
<!-- 根据id更新用户,需要传入用户的id和用户的更新信息(也就是传入User对象,但是user对象中的id必须存在) -->
<update id="updateUser" parameterType="com.huihui.pojo.User">
    update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>

 
 
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

2.Dao接口:

package com.huihui.dao;

import java.util.List;

import com.huihui.pojo.User;

public interface UserDao {

    //根据id查询用户信息
    public User findUserById(int id) throws Exception;

    //根据用户的名称查询用户的信息
    public List<User> findUserByName(String name) throws Exception;

    //添加用户信息
    public void insertUser(User user) throws Exception;

    //删除用户信息
    public void deleteUser(int id) throws Exception;

}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3.Dao接口实现类:

package com.huihui.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.huihui.pojo.User;

public class UserDaoImpl implements UserDao{

    //需要向dao实现类中注入SqlSessionFactory
    //这里通过构造方法注入
    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User findUserById(int id) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        //释放资源
        sqlSession.close();
        return user;
    }

    @Override
    public void insertUser(User user) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.insert("test.insertUser", user);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }

    @Override
    public void deleteUser(int id) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.delete("test.deleteUser", id);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }

    @Override
    public List<User> findUserByName(String name) throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.selectList("test.findUserByUsername", name);
        //释放资源
        sqlSession.close();
        return null;
    }

}

 
 
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

4.加载user.xml文件 
修改SqlMapConfig.xml文件:

  <!-- 加载映射文件 -->
  <mappers>
    <mapper resource="sqlmap/user.xml"/>
  </mappers>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

5.测试代码:

public class UserDaoImplTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    //此方法是运行下面的测试用例的方法之前执行的
    public void setUp() throws Exception{
        //创建sqlSessionFactory
        //mybatis配置文件路径
        String resource = "SqlMapConfig.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void testFindUserById() throws Exception{
        //创建一个userDao的对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        //调用UserDao方法
        User user = userDao.findUserById(1);
        System.out.println(user);
    }
    @Test
    public void testFindUserByName() throws Exception{
        //创建一个userDao对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        //调用UserDao方法
        List<User> list = userDao.findUserByName("张");
        System.out.println(list.size());
    }
}  
 
 
  • 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
  • 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

分析原始Dao开发方式存在的问题:

原始Dao开发中存在以下问题:

  1. Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
  2. 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。
  3. 调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

2.mapper动态代理的方法

实现原理 
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:

  1. Mapper.xml文件中的namespace与mapper接口的类路径相同。
  2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
  4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

只有遵循以上规范,mybatis才可以自动生成mapper接口的实现类代理对象。 
其实以上的规范主要为了相对于dao实现类中的以下方法进行了自动生成:

User user = sqlSession.selectOne("test.findUserById", id);

sqlSession.insert("test.insertUser", user);

sqlSession.delete("test.deleteUser", id);

sqlSession.selectList("test.findUserByUsername", name);
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

1.映射文件(UserMapper.xml文件): 
定义mapper映射文件UserMapper.xml(内容同User.xml一样),需要修改namespace的值为UserMapper接口路径。将UserMapper.xml放在classpath下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">
<!-- namespace :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用(需要修改namespace的值为UserMapper接口路径)。 -->
<mapper namespace="com.huihui.mapper.UserMapper">

<!-- 根据Id获取用户信息 ,返回一条数据-->
<!-- 通过<select>进行数据库查询
id:标识映射文件中的sql
将sql语句封装到mappedStatement对象中,所以将id称为statement的id
parameterType:指定输入参数的类型
#{}:表示一个占位符
#{id}:其中的id表示接收输入的参数,参数的名称就是id,如果输入参数为简单类型,#{}中的参数名可以任意,可以value也可以其它名称。
resultType:指定sql输出结果的所映射的java对象类型。select指定resultType表示将单条记录映射成的java对象。
 -->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.huihui.pojo.User">
    select * from user where id=#{id}
</select>
<!-- 自定义条件查询用户列表,可能返回多条 -->
<!-- 
${}:表示拼接sql串,将接收到的参数的内容不加任何修饰拼接到sql中。
使用${}拼接sql,可能引起sql注入
${value}:接收输入参数的内容,如果传入的类型是简单类型,${}中只能使用value
 -->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="com.huihui.pojo.User">
    select * from user where username like '%${value}%'
</select>

<!-- 添加用户 -->
<!-- 
parameterType:指定输入参数类型为pojo
#{}中指定pojo的属性名,接收到pojo对象的属性值
 -->
<insert id="insertUser" parameterType="com.huihui.pojo.User" >
    insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
    <!-- selectKey将主键返回,需要再返回 -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        select LAST_INSERT_ID()
    </selectKey>
</insert>

<!-- 删除用户 -->
<!-- 根据id删除用户,需要输入id值 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
    delete from user where id = #{id}
</delete>

<!-- 更新用户 -->
<!-- 根据id更新用户,需要传入用户的id和用户的更新信息(也就是传入User对象,但是user对象中的id必须存在) -->
<update id="updateUser" parameterType="com.huihui.pojo.User">
    update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>

 
 
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

2.接口(UserMapper.Java文件) 
接口定义有如下特点:

  1. Mapper接口方法名和Mapper.xml中定义的statement的id相同
  2. Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同
  3. Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同
package com.huihui.mapper;

import java.util.List;

import com.huihui.pojo.User;

/**
 * mapper接口,相当于dao接口
 * 用户管理
 * @author 62347
 *
 */
public interface UserMapper {

    //根据id查询用户信息
    public User findUserById(int id) throws Exception;

    //根据用户名列查询用户列表
    public List<User> findUserByUsername(String name) throws Exception;

    //添加用户信息
    public void insertUser(User user) throws Exception;

    //删除用户信息
    public void deleteUser(int id) throws Exception;

}

 
 
  • 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
  • 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

3.加载UserMapper.xml文件

  <!-- 加载映射文件 -->
  <mappers>
    <mapper resource="mapper/UserMapper.xml"/>
  </mappers>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

4.测试代码:

package com.huihui.mapper;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import com.huihui.pojo.User;

public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    //此方法是运行下面的测试用例的方法之前执行的
    public void setUp() throws Exception{
        //创建sqlSessionFactory
        //mybatis配置文件路径
        String resource = "SqlMapConfig.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception {
        //通过会话工厂得到会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建UserMapper对象,mybatis自动生成mapper代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = userMapper.findUserById(30);
        System.out.println(user);

        sqlSession.close();
    }

    @Test
    public void testFindUserByName() throws Exception {
        //通过会话工厂得到会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建UserMapper对象,mybatis自动生成mapper代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        List<User> list = userMapper.findUserByUsername("张");
        System.out.println(list.size());

        sqlSession.close();
    }

    @Test
    public void testInsertUser() throws Exception {
        //通过会话工厂得到会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建UserMapper对象,mybatis自动生成mapper代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = new User();
        user.setSex("2");
        user.setBirthday(new Date());
        user.setAddress("北京丰台");
        user.setUsername("哒哒哒");

        userMapper.insertUser(user);

        sqlSession.commit();//提交事务
        sqlSession.close();
    }

    @Test
    public void testDeleteUser() throws Exception {
        //通过会话工厂得到会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建UserMapper对象,mybatis自动生成mapper代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        userMapper.deleteUser(30);

        sqlSession.commit();//提交事务
        sqlSession.close();
    }

}

 
 
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 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
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

重点说明:

  1. selectOne和selectList 
    动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
  2. mapper接口输入参数只能有一个,是否不利于系统扩展维护? 
    系统框架中,dao层的代码是被业务层公用的。即使mapper接口中只有一个参数,也可以使用包装类型的pojo满足不同的业务方法的需求。 
    注意:持久层中方法的参数可以是包装类型(eg:map,…..),但是service方法中不建议使用包装类型(原因:不利于业务层的可扩展)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值