zoukankan      html  css  js  c++  java
  • mybatis详解学习之mybatis中非代理模式设置查询参数时是忽略类型的

    非代理使用Mybatis

    一、环境搭建

    1、pom文件

    <project xmlns="http://maven.apache.org/POM/4.0.0"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.mybatis.source.test</groupId>
    	<artifactId>mybatis-pro</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<properties>
    		<slf4j-api.version>1.7.25</slf4j-api.version>
    		<logback.version>1.1.7</logback.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>ognl</groupId>
    			<artifactId>ognl</artifactId>
    			<version>3.0.8</version>
    		</dependency>
    		<dependency>
    			<groupId>org.javassist</groupId>
    			<artifactId>javassist</artifactId>
    			<version>3.24.1-GA</version>
    		</dependency>
    		<dependency>
    			<groupId>org.mybatis</groupId>
    			<artifactId>mybatis</artifactId>
    			<version>3.3.0-SNAPSHOT</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.slf4j</groupId>
    			<artifactId>slf4j-api</artifactId>
    			<version>${slf4j-api.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>ch.qos.logback</groupId>
    			<artifactId>logback-core</artifactId>
    			<version>${logback.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>ch.qos.logback</groupId>
    			<artifactId>logback-access</artifactId>
    			<version>${logback.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>ch.qos.logback</groupId>
    			<artifactId>logback-classic</artifactId>
    			<version>${logback.version}</version>
    		</dependency>
    
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>1.2.17</version>
    		</dependency>
    
    		<dependency>
    			<groupId>commons-logging</groupId>
    			<artifactId>commons-logging</artifactId>
    			<version>1.2</version>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.logging.log4j</groupId>
    			<artifactId>log4j-core</artifactId>
    			<version>2.13.3</version>
    		</dependency>
    
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>8.0.16</version>
    		</dependency>
    
    
    	</dependencies>
    </project>
    

    2、Mybatis主配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <setting name="lazyLoadingEnabled" value="false"/>
        </settings>
        <typeAliases>
            <typeAlias alias="role" type="com.mybatis.learn.bean.Role"/>
        </typeAliases>
        <typeHandlers>
            <typeHandler jdbcType="VARCHAR" javaType="string" handler="com.mybatis.learn.handler.MyStringHandler"/>
        </typeHandlers>
        <!-- 定义数据库的信息,默认使用development数据库构建环境 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC" />
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver" />
                    <property name="url" value="jdbc:mysql://localhost:3306/project_crowd?serverTimezone=UTC" />
                    <property name="username" value="root" />
                    <property name="password" value="123456" />
                </dataSource>
            </environment>
        </environments>
        <!-- 定义映射器 -->
        <mappers>
            <package name="com.mybatis.learn.mapper" />
        </mappers>
    
    </configuration>
    

    3、日志配置文件

    log4j.rootLogger=DEBUG,stdout
    log4j.logger.org.mybatis=DUBUG
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.logDailyFile.layout.ConversionPattern = %5p %d %C:%m%n
    

    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.mybatis.source.test.mapper.RoleMapper">
    	<resultMap type="role" id="roleMap">
    		<id column="id" property="id" javaType="long" jdbcType="BIGINT" />
    		<result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR" />
    		<result column="note" property="note" typeHandler="com.mybatis.source.test.handler.MyStringHandler" />
    	</resultMap>
    	
    	<select id="queryRolesByCondition" parameterType="com.mybatis.source.test.bean.Role" resultMap="roleMap">
    		select * from role where
            1=1
            <if test="id!=null">
                and id=#{id,jdbcType=BIGINT}
            </if>
            <if test="roleName!=null">
                and role_name=#{roleName,jdbcType=BIGINT}
            </if>
            <if test="note!=null">
                and note=#{note,jdbcType=BIGINT}
            </if>
            and tenant_id=#{tenantId,jdbcType=VARCHAR}
    	</select>
    	
    	<select id="getRole" parameterType="long" resultMap="roleMap">
    		select
    		id,role_name as roleName,note from role where id=#{id}
    	</select>
    	<select id="findRole" parameterType="long" resultMap="roleMap">
    		select
    		id,role_name,note from role where role_name like CONCAT('%',#{roleName
    		javaType=string,
    		jdbcType=VARCHAR,typeHandler=com.mybatis.source.test.handler.MyStringHandler},'%')
    	</select>
    	<insert id="insertRole" parameterType="role">
    		insert into
    		role(role_name,note) value(#{roleName},#{note})
    	</insert>
    	<delete id="deleteRole" parameterType="long">
    		delete from role where
    		id=#{id}
    	</delete>
    </mapper>
    

    5、mapper接口

    package com.mybatis.source.test.mapper;
    
    import java.util.List;
    
    import com.mybatis.source.test.bean.Role;
    
    public interface RoleMapper {
    	public Role getRole(Long id);
        public Role findRole(String roleName);
        public int deleteRole(Long id);
        public int insertRole(Role role);
        
        public List<Role> queryRolesByCondition(Role role);
    }
    

    二、非代理方式代码执行

    1、测试代码

    package com.mybatis.source.test.Main;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    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 com.mybatis.source.test.bean.Role;
    import com.mybatis.source.test.mapper.RoleMapper;
    
    public class Main {
    	public static void main(String[] args) {
    		String resource = "mybatis-config.xml";
    		InputStream inputStream = null;
    		try {
    			inputStream = Resources.getResourceAsStream(resource);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		SqlSessionFactory sqlSessionFactory = null;
    		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    		SqlSession sqlSession = null;
    		try {
    			sqlSession = sqlSessionFactory.openSession();
    
    			Map<String,Object> param=new HashMap<>();
    			param.put("id", 1);
    			List<Role> list = sqlSession.selectList("com.mybatis.source.test.mapper.RoleMapper.queryRolesByCondition", param);
    
    			sqlSession.commit();
    
    		} catch (Exception e) {
    			sqlSession.rollback();
    			e.printStackTrace();
    		} finally {
    			sqlSession.close();
    		}
    	}
    }
    

    2、执行结果

    com.mybatis.source.test.mapper.RoleMapper.queryRolesByCondition - ==> 
    Preparing: select * from role where 1=1 and id=? and tenant_id=? 
    com.mybatis.source.test.mapper.RoleMapper.queryRolesByCondition - ==> Parameters: 1(Integer), null
    com.mybatis.source.test.mapper.RoleMapper.queryRolesByCondition - <==      Total: 0
    

    3、结果分析

    RoleMapper.queryRolesByCondition接口的入参是Role,但是在测试代码中,我们传入的是Map对象,发现代码也能运行。

    其原因是因为参数值的获取是通过MetaObject工具类来获取的,代码如下:

    //设置参数
      @Override
      public void setParameters(PreparedStatement ps) throws SQLException {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
          //循环设参数
          for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            if (parameterMapping.getMode() != ParameterMode.OUT) {
              //如果不是OUT,才设进去
              Object value;
              String propertyName = parameterMapping.getProperty();
              if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                //若有额外的参数, 设为额外的参数
                value = boundSql.getAdditionalParameter(propertyName);
              } else if (parameterObject == null) {
                //若参数为null,直接设null
                value = null;
              } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                //若参数有相应的TypeHandler,直接设object
                value = parameterObject;
              } else {
                //除此以外,MetaObject.getValue反射取得值设进去
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                value = metaObject.getValue(propertyName);
              }
              TypeHandler typeHandler = parameterMapping.getTypeHandler();
              JdbcType jdbcType = parameterMapping.getJdbcType();
              if (value == null && jdbcType == null) {
                //不同类型的set方法不同,所以委派给子类的setParameter方法
                jdbcType = configuration.getJdbcTypeForNull();
              }
              typeHandler.setParameter(ps, i + 1, value, jdbcType);
            }
          }
        }
      }
    

    4、MetaObject测试

    采用MetaObject工具类,并不关心对象是什么样的类型,只要给出对象中有什么属性,就可以通过工具类拿到对象对应的属性的值

    package com.mybatis.learn.main;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.reflection.MetaObject;
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    class Person{
        private String name;
        private String address;
    
        public Person(String name, String address) {
            this.name = name;
            this.address = address;
        }
    }
    public class MetaObjectTest {
        static SqlSessionFactory sqlSessionFactory = null;
    
        static{
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        public static void main(String[] args) {
            List<String> fieldNameList=new ArrayList<>();
            fieldNameList.add("name");
            fieldNameList.add("address");
            Map<String,String> map=new HashMap<>();
            map.put("name","张三");
            map.put("address","杭州市");
            //可以访问map中属性为name与address的值
            printFieldValue(map,fieldNameList);
            System.out.println("+++++++++++++++++++++++++");
            Person person=new Person("王五","北京市");
            // 可以访问对象中属性为name与address的值
            printFieldValue(person,fieldNameList);
    
        }
    
        public static void printFieldValue(Object obj, List<String> fieldNames){
            SqlSession sqlSession = sqlSessionFactory.openSession();
            Configuration configuration = sqlSession.getConfiguration();
            MetaObject metaObject=configuration.newMetaObject(obj);
            for (String fieldName:fieldNames){
                Object value = metaObject.getValue(fieldName);
                System.out.println(value);
            }
        }
        
        // 模拟MetaObject对象的getValue方法
         public static void printFieldByReflect(Object obj, List<String> fieldNames){
            if(obj instanceof Map){
                Map<String,Object> map=( Map<String,Object>)obj;
                for(String fieldName:fieldNames){
                    System.out.println(map.get(fieldName));
                }
    
            }else if(obj instanceof Collection){
    
            }else if(obj != null && obj.getClass().isArray()){
    
            }else{
                Class<?> aClass = obj.getClass();
                for(String fieldName:fieldNames){
                    try{
                        Field field = aClass.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        Object o = field.get(obj);
                        System.out.println(o);
    
                    }catch (Exception e){
                        e.printStackTrace();
                    }
    
                }
            }
    
    
        }
    
    
    }
    

    所以在Mybatis对象设置参数值时,一般并不会去校验对象的类型,只关注对象中是否有相应的属性。

  • 相关阅读:
    ThinPHP v5.x安装初始化配置(项目实战)
    Bresenham快速画直线算法
    arm笔记之MOV
    Blackfin DSP的C语言优化之Circular Buffer
    Visual DSP定点数(fract)使用指南
    全局二值化
    Blackfin DSP学习心得与参考资料
    Linux网络配置
    一般方程与参数方程求直线交点
    一个改进的快速排序实现
  • 原文地址:https://www.cnblogs.com/cplinux/p/15046110.html
Copyright © 2011-2022 走看看