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对象设置参数值时,一般并不会去校验对象的类型,只关注对象中是否有相应的属性。

  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/cplinux/p/15046110.html
Copyright © 2011-2022 走看看