Mybatis学习系列(四)Mapper接口动态代理

实现原理及规范

Mapper接口动态代理的方式需要手动编写Mapper接口,Mybatis框架将根据接口定义创建接口的动态代理对象,代理对象的方法体实现Mapper接口中定义的方法。

使用Mapper接口需要遵守以下规范:

1.  Mapper.xml文件中的namespace与mapper接口的类路径相同

2.  Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

3.  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

4.  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

编写Mapper.xml映射文件

定义mapper映射文件ProductMapper.xml,需要修改namespace的值为 ProductMapper接口路径

<?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:此处使用包名+文件名 的形式 -->
<mapper namespace="com.sl.mapper.ProductMapper">
    <!-- 返回自定义类型 注意 selectAllProduct返回的是集合,这种情况下resultType是集合包含的类型,而不能是集合本身 -->
    <select id="selectAllProduct" resultType="com.sl.po.Product">
        select * from products
    </select>
  <select id="selectProductsByVo" resultType="com.sl.po.Product">
        select * from products
        <where>
            <if test="product.cityCode!=null">
               and citycode = #{product.cityCode}
               <!-- citycode = #{cityCode} -->
            </if>
            <if test="product.Name!=null">
                and name like #{product.Name}
            </if>
            <if test="product.Description!=null">
                and description like #{product.Description}
            </if>
        </where>
  </select>  
</mapper>

编写Mapper.java接口

接口定义注意点:

1.  Mapper接口方法名和Mapper.xml中定义的statement的id相同

2.  Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同

3.  Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同

package com.sl.mapper;
import java.util.List;
import com.sl.po.Product;
import com.sl.po.ProductVo;

public interface ProductMapper {
    
    List<Product> selectAllProduct();
    
    List<Product> selectProductsByVo(ProductVo vo);
    
}
View Code
package com.sl.po;

public class ProductVo {

    private int category;
    
    private Product product;
    
    
    public int getCategory() {
        return category;
    }

    public void setCategory(int category) {
        this.category = category;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }
    
    
}
View Code

注册Mapper.xml配置文件(或者Mapper.java接口)

修改SqlMapConfig.xml文件:

<mappers>
        <!-- 注册productMapper.xml文件 -->
        <mapper resource="mapper/productMapper.xml"></mapper> <!-- mapper.xml文件和mapper接口可以不在一个包下  -->
        
        <!-- 注册mapper接口 -->
        <!-- <mapper class="com.sl.mapper.ProductMapper"></mapper>  --> <!--通过注册mapper接口方式: Mapper接口和mapper.xml必须在同一个包下 -->
        
</mappers>

测试方法

//Mapper接口动态代理方式
public class TestProductMapperClient {

    // 定义会话SqlSession
    SqlSession session = null;

    @Before
    public void init() throws IOException {
        // 定义mabatis全局配置文件
        String resource = "SqlMapConfig.xml";

        // 加载mybatis全局配置文件
        // InputStream inputStream =
        // TestClient.class.getClassLoader().getResourceAsStream(resource);

        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(inputStream);
        // 根据sqlSessionFactory产生会话sqlsession
        session = factory.openSession();
    }

    // select by id
    //@Test
    public void testSelectProduct() {

        // 获取mapper接口的代理对象
        ProductMapper productMapper = session.getMapper(ProductMapper.class);

        List<Product> listProduct = productMapper.selectAllProduct();

        for (Product product : listProduct) {
            System.out.println(product);
        }
        // 关闭会话
        session.close();
    }
    
        @Test
        public void testwhereTest() {
            Product product = new Product();
            product.setCityCode("A01");
            product.setName("%国际%");
            //product.setDescription("%xx%");
            //product.setUnitPrice(new BigDecimal(100));
            ProductVo vo = new ProductVo();
            vo.setProduct(product);
            ProductMapper productMapper = session.getMapper(ProductMapper.class);
            List<Product> listProduct = productMapper.selectProductsByVo(vo);
            for (Product pro : listProduct) {
                System.out.println(pro);
            }

            // 关闭会话
            session.close();
        }

}
View Code

      动态代理对象内部调用sqlSession.selectOne()和sqlSession.selectList()实现数据库操作,具体调用哪一个是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

由于参数类型在mapper.xml配置文件中ParameterType配置,所以Mapper.java中接口方法只有一个参数,且类型与mapper.xml中配置的相同(mapper.xml可省略参数类型配置)。

 

转载于:https://www.cnblogs.com/ashleyboy/p/9277048.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis Mapper 实现动态代理的调用思路: 1. 定义 Mapper 接口,该接口可以通过注解或 XML 文件的方式定义 SQL 语句和参数映射关系。 2. 使用 MyBatisMapperFactory 创建 MapperProxyFactory 对象,该对象用于创建 Mapper 接口的代理对象。 3. 创建 MapperProxy 对象,该对象实现了 InvocationHandler 接口,用于处理代理对象方法的调用。 4. 通过 MapperProxyFactory 对象的 newInstance 方法创建 Mapper 接口的代理对象,该对象会被传入 MapperProxy 对象的构造函数中。 5. 通过代理对象调用 Mapper 接口的方法时,会被 MapperProxy 对象的 invoke 方法拦截,该方法会根据方法名和参数类型动态生成 SQL 语句,并通过 MyBatis 的 SqlSession 执行 SQL 语句。 下面是使用 Java 代码实现 MyBatis Mapper 动态代理的调用过程: 1. 定义 Mapper 接口 ```java public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User getUserById(int id); } ``` 2. 创建 MapperProxyFactory 对象 ```java public class MapperFactory { private final Configuration configuration; public MapperFactory(Configuration configuration) { this.configuration = configuration; } public <T> T getMapper(Class<T> mapperInterface) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, new MapperProxy(configuration, mapperInterface)); } } ``` 3. 创建 MapperProxy 对象 ```java public class MapperProxy<T> implements InvocationHandler { private final SqlSession sqlSession; private final Class<T> mapperInterface; public MapperProxy(Configuration configuration, Class<T> mapperInterface) { this.sqlSession = new SqlSessionFactoryBuilder().build(configuration).openSession(); this.mapperInterface = mapperInterface; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String statement = mapperInterface.getName() + "." + method.getName(); MappedStatement mappedStatement = sqlSession.getConfiguration().getMappedStatement(statement); if (mappedStatement == null) { throw new RuntimeException("Can't find mapped statement for " + statement); } Object result = null; switch (mappedStatement.getSqlCommandType()) { case SELECT: result = sqlSession.selectOne(statement, args); break; case INSERT: result = sqlSession.insert(statement, args); break; case UPDATE: result = sqlSession.update(statement, args); break; case DELETE: result = sqlSession.delete(statement, args); break; default: throw new RuntimeException("Unknown SqlCommandType " + mappedStatement.getSqlCommandType()); } sqlSession.commit(); return result; } } ``` 4. 创建 Mapper 接口的代理对象 ```java Configuration configuration = new Configuration(); configuration.addMapper(UserMapper.class); MapperFactory mapperFactory = new MapperFactory(configuration); UserMapper userMapper = mapperFactory.getMapper(UserMapper.class); ``` 5. 调用 Mapper 接口的方法 ```java User user = userMapper.getUserById(1); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值