MeatObject是Mybatis的工具类,通过MetaObject获取和设置对象的属性值。
返回结果:
基本的pojo对象:
MetaObject提供了一个工具类:
当调用 SystemMetaObject 获取 MetaObject 对象时,每次均 new DefaultReflectorFactory() 了一个反射工厂类。
继续查看:
这个类并没有做很复杂的 *** 作,就是获取object的type类型,且存储到Map中。当同一个object调用 forObject() 时,后续调用可以在缓存中获取反射对象。
但注意: SystemMetaObject 方法因为每次均new了一个新的 DefaultReflectorFactory 工厂。若每次在方法中调用 SystemMetaObjectforObject 获取 MetaObject 对象。同一个对象可能不会走缓存。
推荐做法: 将 DefaultReflectorFactory 声明为静态变量:
在创建 MetaObject 对象的时候,就会将传入的Object对象的所有反射对象都缓存起来。后续调用 metaObjectsetValue 等方法时,直接在缓存中获取到反射对象,然后执行反射 *** 作。
创建MetaObject对象时,选择不同的Wrapper进行包装。
以普通的pojo为例,创建 BeanWrapper 对象,在 forClass 方法中会遍历object的所有方法。获取反射对象。
到此处:
到达此处,判断 缓存 中是否存在某对象的解析结果:
注意: MetaObjectforObject 会将object结果缓存起来,后续在使用MetaObjectforObject创建对象时,直接在缓存中获取。
若没有存在,则调用 new Reflector(type); 去创建cache对象。
总方法:
2 删除方法的前缀,获取属性名:
3 key为属性名,value是集合:
4 将局部变量放入到属性集合中:
5 放入到属性变量中
设置分词器:
>
使用mybatis-plus 代码生成器时,mysql 字段为 DateTime。映射实体类的属性类型为LocalDateTime,查询时显示字段不能映射上。才发现java Bean 字段不是Date。
修改代码生成器代码:
// 数据源配置DataSourceConfig dsc = new DataSourceConfig();
dscsetTypeConvert(new MySqlTypeConvert() {//修改mysql datetime 生成实体类 date 类型
@Override
public DbColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
if ( fieldTypetoLowerCase()contains( "datetime" ) ) {
return DbColumnTypeDATE;
}
return (DbColumnType) superprocessTypeConvert(globalConfig, fieldType);
}
});
再次运行程序生成实体类:
问题解决:
入口:一般会在DAO层配置中,比如下面是我的配置
在这里面,我们配置了id为sqlSessionFactory的bean。那么这也是我们的入口
由此可以看出,id为sqlSessionFactory的bean默认是DefaultSqlSessionFactory。Mybatis的官方推荐,SqlSessionFactory最好是做成单例的,不需要频繁创建。
通过api获取session的方式
那么我们就看DefaultSqlSessionFactoryopenSession方法,如下
再看DefaultSqlSessiongetMapper方法
这个 configuration 对象是在哪里创建,又是哪里传入的呢?其实是从一开始的 SqlSessionFactoryBean 中创建好后,赋值给 SqlSessionFactoryBuilder 的build的方法参数,一路传到了 DefaultSqlSession 中。也就是说 configuration 是隶属于 DefaultSqlSessionFactory 的,生命周期很长。
那 configuration 究竟有什么呢?
原来,所有的Mapper接口被扫描后,都会被存储在Configuration的mapperRegistry里的Map中。而且 key = Mapper class value = 创建当前Mapper的工厂 。
接着看 configurationgetMapper() 方法
那我们知道了 knownMappersget(type) 返回的是一个创建Mapper的工厂 MapperProxyFactory 。
接下来我们看看 MapperProxyFactory 是如何创建的。直接看 MapperProxyFactory 的 newInstance(SqlSession sqlSession) 方法
可以清楚的看到,通过jdk的动态代理创建了代理类。那么我们需要关注一下,代理类的InvocationHandler做了哪些事情
这里需要注意methodCache这个Map,不是保存在本类里的。看MapperProxy的有参构造传进来的。那么谁创建的MapperProxy呢?上面我们说了是Mapper对应的Mapper工厂MapperProxyFactory。这个对象也是保存在 Configuration 中,生命周期很长。
这就解释了,为什么 官网上推荐,让Mapper的实现类 用后就可以舍弃(做局部变量),但是这样每次都去创建难道不耗时,答案是不耗时,因为核心的 MapperMethod 都已经被缓存起来了。
*** 作。具体的步骤如下:
获取 MyBatis 中的 MappedStatement 对象。可以通过 SqlSession 的 getConfiguration() 方法获取 Configuration 对象,然后再通过 Configuration 对象的 getMappedStatement() 方法获取 MappedStatement 对象。
从 MappedStatement 对象中获取 BoundSql 对象,即 SQL 语句绑定的参数对象。
从 BoundSql 对象中获取 SQL 语句字符串。可以通过调用 getSql() 方法获取 SQL 语句字符串。
对 SQL 语句进行相应的 *** 作。例如,可以对 SQL 语句进行修改、输出等 *** 作。
Java 通过反射获取 MyBatis 中的 SQL 语句的代码示例:
SqlSession sqlSession = sqlSessionFactoryopenSession();
try {
// 获取 MappedStatement 对象
MappedStatement mappedStatement = sqlSessiongetConfiguration()getMappedStatement("comexamplemapperselectUser");
// 获取 BoundSql 对象
BoundSql boundSql = mappedStatementgetBoundSql(paramObject);
// 获取 SQL 语句字符串
String sql = boundSqlgetSql();
// 对 SQL 语句进行相应的 *** 作
//
} finally {
sqlSessionclose();
}
需要注意的是,在使用反射获取 SQL 语句时,要注意保护用户隐私和安全,以免发生 SQL 注入等问题。
mybaits把date类型传到数据库的是内部自己做了映射的,程序员无需特殊处理。
1、在使用MyBatis3做数据持久层,当字段中有Date和DateTime类型时,插入数据库时要将实体的属性设置成Timestamp就会对应数据库的DateTime类型,Date会对应数据库的Date类型。
2、举例说明:
<result column="modified_date" jdbcType="TIMESTAMP" property="modified_date" javaType="javasqlTimestamp" />
<result column="date" jdbcType="DATE" property="date" javaType="javautilDate" />
注意:在MyBatis映射文件中要表明映射类型。
3、插入结果:
学习了Spring之后,我们已经了解如何将一个类作为Bean交由IoC容器管理,也就是说,现在我们可以通过更方便的方式来使用Mybatis框架,我们可以直接把SqlSessionFactory、Mapper交给Spring进行管理,并且可以通过注入的方式快速地使用它们。
因此,我们要学习一下如何将Mybatis与Spring进行整合,那么首先,我们需要在之前知识的基础上继续深化学习。
在之前,我们如果需要创建一个JDBC的连接,那么必须使用 DriverManagergetConnection() 来创建连接,连接建立后,我们才可以进行数据库 *** 作。
而学习了Mybatis之后,我们就不用再去使用 DriverManager 为我们提供连接对象,而是直接使用Mybatis为我们提供的 SqlSessionFactory 工具类来获取对应的 SqlSession 通过会话对象去 *** 作数据库。
那么,它到底是如何封装JDBC的呢?我们可以试着来猜想一下,会不会是Mybatis每次都是帮助我们调用 DriverManager 来实现的数据库连接创建?我们可以看看Mybatis的源码:
在通过 SqlSessionFactory 调用 openSession 方法之后,它调用了内部的一个私有的方法 openSessionFromDataSource ,我们接着来看,这个方法里面定义了什么内容:
也就是说,我们的数据源配置信息,存放在了 Transaction 对象中,那么现在我们只需要知道执行器到底是如何执行SQL语句的,我们就知道到底如何创建 Connection 对象了,就需要获取数据库的链接信息了,那么我们来看看,这个 DataSource 到底是个什么:
我们发现,它是在 javaxsql 定义的一个接口,它包括了两个方法,都是用于获取连接的。因此,现在我们可以断定,并不是通过之前 DriverManager 的方法去获取连接了,而是使用 DataSource 的实现类来获取的,因此,也就正式引入到我们这一节的话题了:
数据库链接的建立和关闭是极其耗费系统资源的 *** 作,通过DriverManager获取的数据库连接,
一个数据库连接对象均对应一个物理数据库连接,每次 *** 作都打开一个物理连接,使用完后立即关闭连接,频繁的打开、关闭连接会持续消耗网络资源,造成整个系统性能的低下。
因此,JDBC为我们定义了一个数据源的标准,也就是 DataSource 接口,告诉数据源数据库的连接信息,并将所有的连接全部交给数据源进行集中管理,当需要一个 Connection 对象时,可以向数据源申请,数据源会根据内部机制,合理地分配连接对象给我们。
一般比较常用的 DataSource 实现,都是采用池化技术,就是在一开始就创建好N个连接,这样之后使用就无需再次进行连接,而是直接使用现成的 Connection 对象进行数据库 *** 作。
当然,也可以使用传统的即用即连的方式获取 Connection 对象,Mybatis为我们提供了几个默认的数据源实现,我们之前一直在使用的是官方的默认配置,也就是池化数据源:
一共三个选项:
那么我们先来看看,不使用池化的数据源实现,它叫做 UnpooledDataSource ,我们来看看源码:
首先这个类中定义了很多的成员,包括数据库的连接信息、数据库驱动信息、事务相关信息等。
我们接着来看,它是如何实现 DataSource 中提供的接口的:
实际上,这两个方法都指向了内部的一个 doGetConnection 方法,那么我们接着来看:
首先它将数据库的连接信息也给添加到 Properties 对象中进行存放,并交给下一个 doGetConnection 来处理,套娃就完事了呗,接着来看下一层源码:
到这里,就返回 Connection 对象了,而此对象正是通过 DriverManager 来创建的,因此,非池化的数据源实现依然使用的是传统的连接创建方式,那我们接着来看池化的数据源实现,它是 PooledDataSource 类:
我们发现,在这里的定义就比非池化的实现复杂得多了,因为它还要考虑并发的问题,并且还要考虑如何合理地存放大量的链接对象,该如何进行合理分配,因此它的玩法非常之高级。
首先注意,它存放了一个UnpooledDataSource,此对象是在构造时就被创建,其实创建Connection还是依靠数据库驱动创建,我们后面慢慢解析,首先我们来看看它是如何实现接口方法的:
可以看到,它调用了 popConnection() 方法来获取连接对象,然后进行了一个代理,我们可以猜测,有可能整个连接池就是一个类似于栈的集合类型结构实现的。那么我们接着来看看 popConnection 方法:
经过上面一顿猛如虎的 *** 作之后,我们可以得到以下信息:
如果最后得到了连接对象(有可能是从空闲列表中得到,有可能是直接创建的新的,还有可能是经过回收策略回收得到的)。
那么连接(Connection)对象一定会被放在活跃列表中(stateactiveConnections)
那么肯定有一个疑问,现在我们已经知道获取一个链接会直接进入到活跃列表中,那么,如果一个连接被关闭,又会发生什么事情呢,我们来看看此方法返回之后,会调用 getProxyConnection 来获取一个代理对象,实际上就是 PooledConnection 类:
它直接代理了构造方法中传入的Connection对象,也是使用JDK的动态代理实现的,那么我们来看一下,它是如何进行代理的:
那么我们最后再来看看 pushConnection 方法:
这样,我们就已经完全了解了Mybatis的池化数据源的执行流程了。
只不过,无论Connection管理方式如何变换,无论数据源再高级,我们要知道,它都最终都会使用 DriverManager 来创建连接对象,而最终使用的也是 DriverManager 提供的 Connection 对象。
通过了解数据源,我们已经清楚,Mybatis实际上是在使用自己编写的数据源(数据源有很多,之后我们再聊其他的)默认使用的是池化的数据源,它预先存储了很多的连接对象。
那么我们来看一下,如何将Mybatis与Spring更好的结合呢,比如我们现在希望将SqlSessionFactory交给IoC容器进行管理,而不是我们自己创建工具类来管理(我们之前一直都在使用工具类管理和创建会话)
首先导入依赖:
在mybatis-spring依赖中,为我们提供了SqlSessionTemplate类,它其实就是官方封装的一个工具类,我们可以将其注册为Bean,这样我们随时都可以向IoC容器索要,而不用自己再去编写一个工具类了,我们可以直接在配置类中创建:
最后成功得到Student实体类,证明 SqlSessionTemplate 成功注册为Bean可以使用了。
虽然这样已经很方便了,但是还不够方便,我们依然需要手动去获取Mapper对象,那么能否直接得到对应的Mapper对象呢,我们希望让Spring直接帮助我们管理所有的Mapper,当需要时,可以直接从容器中获取,我们可以直接在配置类上方添加注解:
这样,Spring会自动扫描所有的Mapper,并将其实现注册为Bean,那么我们现在就可以直接通过容器获取了:
请一定注意,必须存在 SqlSessionTemplate 或是 SqlSessionFactoryBean 的Bean,否则会无法初始化(毕竟要数据库的链接信息)
我们接着来看,如果我们希望直接去除Mybatis的配置文件,那么改怎么去实现呢?
我们可以使用 SqlSessionFactoryBean 类:
首先我们需要创建一个数据源的实现类,因为这是数据库最基本的信息,然后再给到 SqlSessionFactoryBean 实例,这样,我们相当于直接在一开始通过IoC容器配置了 SqlSessionFactory ,只需要传入一个 DataSource 的实现即可。
删除配置文件,重新再来运行,同样可以正常使用Mapper。
从这里开始,通过IoC容器,Mybatis已经不再需要使用配置文件了,之后基于Spring的开发将不会再出现Mybatis的配置文件。
一、mybatis传递多个参数时获取
parameterType="JavautilMap",参数依次为:param1,param2,param3
或者 #{0},#{1},#{2}。。。。。
二、条件判断
<where>
<if test="param1 != null and param1 != ''">
and tkind = #{param1}//#号获取的是字符串,$获取的数值
</if>
<where>
传一个参数时:test中用 _parameter
匹配bean属性和表中字段
<resultMap id="tchannel" type="comhtcfwebsitemodelpojoTChannel">
<result property="id" column="id" />
<result property="kind" column="kind" />
<result property="lob" column="lob" />
</resultMap>
三、特殊字符
<![CDATA[ ]]>
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String nowDate = sdfformat(new Date());
实体类的date可以转成string,sql语句写一句to_date就好了
以上就是关于mybatis的反射工具类—MetaObject(反射对象类)全部的内容,包括:mybatis的反射工具类—MetaObject(反射对象类)、mybatisplus 怎么修改数据、Mybatis源码分析1-如何获取Mapper实现类等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)