Java数据类型在JPA中是如何映射到Mysql数据库(ex:5.7)

前两天有位学弟问我问题,说他在使用JPA的过程当中遇到一个java类型和mysql类型映射问题,而且在使用TimeStamp 的时候出了错。咱们这里从源码角度宏观看一下是如何映射的,这里jpa实现是 hibernatejava

start

这里只分享一些重点的,其余的非重点的跳过mysql

当咱们在jpa中save一个对象的时候,程序毋庸置疑先拿到一个数据库链接,而后把sql语句怼过去。这sql语句是很好实现的,无非就是先判断主键有没有值,若是有值,就先select一下主键的值看是否有数据行,若是有,接下来就是update操做,没有就是insert操做。若是主键为空,就直接insert了。程序很容易实现后面的insert和update操做的预编译模板化代码生成,这里模板化代码就像这种 insert into tt (time1, time2, time3, time4) values (?, ?, ?, ?),有了模板化sql,接下来就是重点的绑定数据了,如何把java里的对象转成sql语句里的值。有人说直接序列化?对于各类复杂的类型和注解映射,jpa怎么处理的呢。sql

跳过一堆代理的代码,咱们看重点数据库

这里咱们直接看首次执行的过程,由于我也是在测试用例里执行,因此一切都得初始化。安全

这里的作法是获取实体对象的映射相关描述的实体用于持久化的,这里先获取工厂对象获取到元模型,而后再获取持久化描述对象多线程

获取到持久化描述对象,而后进行save操做,并发

这里展现一下 持久化描述对象的字段高并发

其实这个对象字段很是多,还有不少没显示,你们能够自行参看 EntityPersister 接口,很明显这个对象记录了整个映射的信息,包括字段上的注解信息,有了它咱们就能够进行映射。测试

这里对每一个字段进行映射hibernate

debug的时候会发现,后面的对象都是泛型的

最终调用doBind,不一样类型,使用不一样的对象,咱们这里debug的时候遇到的是TimeStamp类型对应的对象

好比

AbstractSingleColumnStandardBasicType<T> 实现类是 TimeStampType

BasicBinder<J> 实现类是TimeStampTypeDescriptor

这里是对 TimeStampTypeDescriptor 对象的获取 和 调用该对象的bind操做


意外发现!!!!!

单例模式


接下来就是重点的清晰的 类型转换操做啦

到了这里调用的就不是jpa的逻辑了

PreparedStatement 类是 import java.sql.PreparedStatement下的 ,到这时候 有可能就有小伙伴问了,为何调来调去仍是调用了java的基础包???

难道仍是基础包作的转换???

其实这里的答案很简单,确实调了基础包,可是!调的是基础包的接口,他的实如今哪呢,这就是传说中的JDBC,这里我使用的是mysql,因此调用的就是com.mysql.cj.jdbc下的 ClientPreparedStatement

这就是转换代码,由jdbc实现,因此这就是驱动为何那么重要,不一样数据库不一样实现

这里代码就很简单了,不过有没有发现 转换只是把时间戳转换为了yyyy-MM-dd HH:mm:ss形式 插入到数据库的,其实这里就是mysql timestamp存储的奥秘,你们能够自行百度一下了解一下。

这里使用了一个类让我困惑,每一个学java的都应该会据说过 SimpleDateFormat这个类有高并发下多线程安全问题,那为何,MySQL jdbc这么大胆呢?

线程安全解决

这里互斥变量就是 JdbcConnection

当获取不到链接的时候,线程互斥会报出 Statement.AlreadyClosed

至于后面那个 getConnectionMutex()调用,这里说出我我的猜测,找资料没找到,看了debug内容,猜测是

同一个ClientPreparedQueryBindings 每次只能对应一个JdbcConnection对象,因此只有共用同一个JdbcConnection对象时才会出现线程安全问题,因此这里互斥变量为 JdbcConnection,我的看法,你们当心点看

以上纯属我的理解,你们审视着看

相关文章
相关标签/搜索