mapper代理原理

一、原始dao层开发
 我们需要做的就是,首先建立一个会话工厂(SqlSessionFactory),然后用会话工厂创建会话(SqlSession)。然后通过读取配置文件得到sql语句,执行,然后返回数据给dao层的对象。具体操作如下

首先,在原来的基础上创建一个dao层的接口。

public  interface  UserDao  {
//根据id查询用户信息
        public  User  findUserById(int  id)throws   Exception;
       //添加用户信息
        public  void   insertUser(User  user)throws    Exception;
//删除用户信息
public  void   deleteUser(int  id)throws  Exception;
}
然后写一个dao层的实现类
 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();
 }
 
 }
然后就是对我们写的代码的测试
public  void  setUp()throws  Exception{

//创建sqlSessionFactory
//mybatis配置文件
String resource="SqlMapConfig.xml";

//得到配置文件流
InputStream   inputStream = Resource.getResourceAsStream(resource);

//创建会话工厂,传入mybatis的配置文件信息
 sqlSessionFactory = new  SqlSessionFactoryBuilder().build(inputStream );

public    void  testFindUserById()throws  Exception{

//创建UserDao 的对象
UserDao  userDao = new    UserDaoImpl(sqlSessionFactory);

//调用UserDao的方法

User   user = userDao.findUserById(1);

System.out.println(user);


}

}

这样开发存在的问题
1.dao接口的实现类中存在大量的重复代码,这些代码会增加程序员的工作量。
2.在实现类中,SqlSession的方法在调用映射文件中的sql语句时将statement的id(其中 的"test.findUserById"便是statment的id)硬编码了。

3.调用SqlSession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入的不是Dao方 法中的参数类型,在编译的时候也不会报错,不利于程序的开发。
    
    为了解决这些问题,我们通过满足一些规范就将实体层的实现类的开发省去,由mybatis框架提供的代理实现类替我们去动态的调用我们的映射文件,然后去执行类中的方法。

mapper代理方法的原理
这之前,先声明一下,使用mapper代理的时候,命名和之前的不太一样。这里的接口命名由原来的** 改为**Mapper,比如说原来的User接口,现改为UserMapper。其内容和本质没有变,只是换了一个命名规范。除了接口外映射文件也是由 User.xml改为UserMapper.xml其内容不变。
mapper代理方法的思路是,程序员接着写持久层的接口。


和对应每个接口的配置文件

在我们的原来的方法中需要再写一个接口的实现类,用来构建会话工厂(SqlSessionFactory)和对应的会话(SqlSession)然后通过会话去读取映射文件中的sql语句(这里不准确,不过可以这么理解)。那么我么就可以在这个实体类上做点文章了:
    1.我们可以创建一个代理类,在我们相应的接口被调用的时候,代理类就会创建这个对象,创建会话工厂和会话并不难。
    2.还有就是我们的sqlSession对象调用的方法名称,这个很好理解,对应的是我们映射文件的标签。
    3.那么接下来就是传入参数和接收返回值的问题了:
    3.1 传入参数:我们总共需要传入两个参数,一个是映射文件的statement的id的字符串,另外一个是执行需要的参数。 比较困难的是,这个字符串的生成 问题。我们的每个方法到底对应的是哪个映射文件的statement的id。对于这个问题,mybatis给出了我们的解决方法:我们的实体层对象读到的 字符串是这样的:test.insertUser
    可以将这个id分为两部分,其中的test是我们的映射文件中的namespace的值,这个值让它和 持久层接口的地址一致,这样就使得代理对象可以通过接口的地址动态的生成id的前半部分,也就是test的这一部分;而后半部分则是让映射文件中的 Statement的id和接口的方法一致。
    也就是说,用户在调用接口的某一个方法的时候,mybatis可以根据接口地址和对应的方法名生成sqlsession对象的方法传入的字符串。这样就解决了传入参数中的字符串的问题了。
    还有就是第二个问题:我们的传入具体参数,mybatis规定,传入参数类型必须和接口的传入参数类型一致。这样,我们的传入参数类型就搞定了。
    3.2传入参数搞定了以后,返回值也就搞定了,跟传入参数的规定一样,返回值的类型要求和接口返回值一致,这样就可以在代理类中将返回值传出了。
    这些搞定了,我们就可以使用代理对象代替我们的实体层具体实现类了。
    至此,这些问题就差不多都解决了,不过还有一个问题:我们的select方法返回值问题,代理对象到底是用selectont方法去查询数 据库呢还是使用selectlist方法呢?这个跟我们的接口(mapper)的返回值类型有关——如果mapper方法返回单个pojo对象(非集合对 象),代理对象内部通过selectOne查询数据库;如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。

mapper代理方法


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值