Java单元测试实践-26.使用JPA自动创建数据库表_java jpa test case-程序员宅基地

技术标签: Java  java  单元测试  jpa  

Java单元测试实践-00.目录(9万多字文档+700多测试示例)
https://blog.csdn.net/a82514921/article/details/107969340

1. 使用JPA自动创建数据库表

以上在单元测试中使用H2数据库的方法,需要在连接数据库时指定数据库建表语句,建表语句需要从数据库服务器获取,由于不同的数据库建表语句存在一些差别,可能并不能直接在H2数据库中使用(如前文所述MySQL建表语句中H2数据库中存在部分不支持),不是最佳的选择。

可以在单元测试中使用JPA,利用JPA根据Entity自动创建数据库表的功能,屏蔽不同数据库的建语句的差异,简化处理H2数据库建表语句的操作。

1.1. JPA相关

1.1.1. 生成JPA Entity

JPA相关资料整理及根据数据库表生成JPA Entity的Java组件增强版使用说明,可参考 https://github.com/Adrninistrator/jpa-entity-generator-enhance ,在开源项目的基础上进行了优化。

1.1.2. EntityManager

参考ejb-3_0-fr-spec-persistence.pdf,“3.1 EntityManager”。

EntityManager实例与持久性上下文关联。持久性上下文是一组Entity实例,对于任何持久性Entity标识,都有一个唯一的Entity实例。持久性上下文对Entity实例及其生命周期进行管理。EntityManager接口定义了用于与持久性上下文进行交互的方法。EntityManager API用于创建和删除持久Entity实例,通过主键查找Entity,以及查询Entity。

1.1.3. EntityManagerFactory

参考ejb-3_0-fr-spec-persistence.pdf,“5.4 The EntityManagerFactory Interface”。

应用程序使用EntityManagerFactory接口来获取应用程序管理的EntityManager。当应用程序使用完EntityManagerFactory后,在应用程序关闭时,应关闭EntityManagerFactory。一旦EntityManagerFactory关闭,则其所有EntityManager都被视为处于关闭状态。

1.1.4. JPA自动建表参数配置

Hibernate实现了JPA规范。参考 https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#schema-generation 。

Hibernate允许从Entity映射生成数据库。

schema自动生成的功能对于测试非常有用,但不建议在生产环境中使用。

从Entity映射生成模式的过程称为HBM2DDL。

参考 https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#configurations-hbmddl 。

hibernate.hbm2ddl.auto参数用于设置为在SessionFactory生命周期中自动执行SchemaManagementTool操作。支持的参数值如下所示:

参数值 说明
none 不执行任何操作(默认值)
create-only 创建数据库
drop 删除数据库
create 先删除数据库,再创建数据库
create-drop 在SessionFactory创建时删除schema并重新创建,当SessionFactory关闭时删除schema
validate 验证数据库schema
update 更新数据库schema

经测试,设置hibernate.hbm2ddl.auto=update,在应用启动时,若数据库表不存在时会创建;对于已存在的数据库表,缺失的字段会增加,多余的字段不会删除。

1.1.5. 自动建表时打印SQL语句

参考 https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#_sql_statement_logging 。

当hibernate.show_sql参数值为true时,会在控制台打印所有的SQL语句,该参数默认值为false。

当hibernate.format_sql参数值为true时,会在日志和控制台中以更直观的方式打印SQL。

1.1.6. hibernate依赖组件

参考 https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html_single/#d0e215 。

兼容JPA 2.0的Hibernate EntityManager建立在Hibernate core和Hibernate Annotations之上。从3.5版开始,将所有必需的模块捆绑在一个Hibernate发行版中:

模块 说明
Hibernate Core 原生Hibernate API和核心引擎
Hibernate Annotations 基于注释的映射
Hibernate EntityManager JPA 2.0 API和livecycle语义实现

可以添加对org.hibernate:hibernate-entitymanager的依赖,所有必须的依赖例如hibernate-core与hibernate-annotations会被传递地拉取。

org.hibernate:hibernate-entitymanager新版(5.4.11.Final及之后)已被移动至org.hibernate:hibernate-core,可使用org.hibernate:hibernate-core:5.4.12.Final。

由于test模块中的Entity使用了Lombok,因此还需要添加依赖“testAnnotationProcessor ‘org.projectlombok:lombok:1.18.12’”。

1.1.7. Spring JPA配置

1.1.7.1. Spring JPA

参考 https://docs.spring.io/spring-framework/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/#orm-jpa 。

Spring JPA可以使用org.springframework.orm.jpa包,对JPA提供了全面的支持,通过与Hibernate或JDO集成的方式。

Spring JPA提供了三种设置JPA EntityManagerFactory的方式,应用程序会使用其获取EntityManager。包括LocalEntityManagerFactoryBean、从JNDI获取EntityManagerFactory、LocalContainerEntityManagerFactoryBean。

1.1.7.2. JpaVendorAdapter

参考 https://docs.spring.io/spring-framework/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/#orm-jpa-dialect 。

JpaDialect实现可以启用Spring支持的一些高级功能,通常以特定于供应商的方式。

JpaVendorAdapter是主要用于Spring的全功能LocalContainerEntityManagerFactoryBean设置的更广泛的提供程序适配器装置。JpaVendorAdapter将JpaDialect的功能与其他特定于提供程序的默认值结合在一起。指定HibernateJpaVendorAdapter或EclipseLinkJpaVendorAdapter分别是为Hibernate或EclipseLink自动配置EntityManagerFactory设置的最便捷方法。

参考 https://docs.spring.io/spring-framework/docs/4.3.26.RELEASE/javadoc-api/org/springframework/orm/jpa/JpaVendorAdapter.html 。

JpaVendorAdapter是SPI接口,允许将特定于供应商的行为插入Spring的EntityManagerFactory创建者中。

AbstractJpaVendorAdapter类实现了JpaVendorAdapter接口,AbstractJpaVendorAdapter类的子类包括OpenJpaVendorAdapter、HibernateJpaVendorAdapter、EclipseLinkJpaVendorAdapter。

1.1.7.3. LocalContainerEntityManagerFactoryBean

参考 https://docs.spring.io/spring-framework/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/#orm-jpa-setup-lcemfb 。

使用LocalContainerEntityManagerFactoryBean可在基于Spring的应用程序环境中提供完整的JPA功能。包括Web容器(例如Tomcat)以及独立应用程序和集成测试。

LocalContainerEntityManagerFactoryBean可以完全控制EntityManagerFactory的配置,适用于需要细粒度自定义的环境。LocalContainerEntityManagerFactoryBean创建了一个PersistenceUnitInfo实例,基于persistence.xml文件、dataSourceLookup策略和指定的loadTimeWeaver。可以使用JNDI之外的自定义数据源并控制编织过程。

LocalContainerEntityManagerFactoryBean是最强大的JPA设置选项,可以在应用程序中进行灵活的本地配置。支持链接到已存在的JDBC数据源的链接,同时支持本地和全局事务等功能。

参考 https://docs.spring.io/spring-framework/docs/4.3.26.RELEASE/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html ,LocalContainerEntityManagerFactoryBean包括以下属性:

  • dataSource

dataSource参数用于指定JPA持久性提供程序用于访问数据库的JDBC数据源。这种方法传入一个Spring管理的DataSource,是将JDBC配置保留在persistence.xml中的一种替代方法。
在JPA的角度,这里传递的数据源将用作传递给持久性提供程序的PersistenceUnitInfo的“ nonJtaDataSource”,并覆盖persistence.xml中的数据源配置(如果有)。

注意:仅在未指定外部PersistenceUnitManager的情况下适用以上指定数据源的方法。

  • jpaVendorAdapter

通过jpaVendorAdapter参数可以为所需的JPA提供程序指定JpaVendorAdapter实现(如果有)。会给定的提供程序初始化适当的默认值。

  • packagesToScan

packagesToScan参数设置对classpath中的Entity类使用基于Spring的扫描,而不是使用JPA对jar文件中带有persistence.xml中的标记的标准扫描。当使用基于Spring的扫描时,不需要persistence.xml,所需要做的就是指定要搜索的基本包。

packagesToScan参数默认为无。指定包以在classpath中搜索对Entity类的自动检测。类似于Spring的组件扫描功能(ClassPathBeanDefinitionScanner)。

注意:仅在未指定外部PersistenceUnitManager的情况下适用以上指定packagesToScan参数的方法。

  • jpaPropertyMap

指定Map形式的JPA属性,传给Persistence.createEntityManagerFactory()方法。

可在XML的bean定义中通过“map”或“props”元素填充。

jpaPropertyMap属性的设置方法包括setJpaPropertyMap()与setJpaProperties()。

可使用jpaProperties属性通过setJpaProperties()方法设置JPA属性,效果相同。setJpaProperties()方法支持在XML的bean定义中通过“props”元素填充,或通过"value"元素指定字符串格式数据填充,由PropertiesEditor解析。

1.2. JPA自动建表总结

在项目中引入Hibernate JPA实现,可以应用启动时通过Entity类自动创建对应的数据库表,可以屏蔽不同数据库的建表语句的细节差异。JPA仅用于自动创建数据库表,不通过JPA执行数据库操作。Entity类生成可以使用Java完成。

在项目中需要引入依赖javax.persistence:javax.persistence-api与org.hibernate:hibernate-core,以及lombok。

在Spring XML文件中需要定义LocalContainerEntityManagerFactoryBean对应的bean,将dataSource属性指定项目中使用的数据源,jpaVendorAdapter属性使用HibernateJpaVendorAdapter,packagesToScan属性指定Entity类所在的包,jpaProperties属性指定JPA属性,hibernate.hbm2ddl.auto应为update,以自动建表。

1.3. JPA自动建表配置

可参考示例项目中的JPA自动建表配置。

1.3.1. 添加依赖

在Gradle脚本中,添加了以下依赖:

"javax.persistence:javax.persistence-api:2.2",
"org.hibernate:hibernate-core:5.4.12.Final"

testAnnotationProcessor 'org.projectlombok:lombok:1.18.12'

1.3.2. Spring XML配置

参考示例项目src\test\resources\springJpa\springJpa.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Spring JPA配置 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!-- 配置JPA使用的数据源 -->
        <property name="dataSource" ref="dataSource"/>

        <!-- 配置JPA提供程序适配器,使用Hibernate -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>

        <!-- 配置JPA Entity所在的包 -->
        <property name="packagesToScan">
            <array>
                <value>adrninistrator.test_jpa.entity</value>
                <value>adrninistrator.test_jpa.entity2</value>
            </array>
        </property>

        <!-- 配置JPA属性 -->
        <property name="jpaProperties">
            <value>
                # 自动创建或更新数据库表
                hibernate.hbm2ddl.auto=update
                # 打印SQL语句
                hibernate.show_sql=true
                hibernate.format_sql=true
            </value>
        </property>
    </bean>
</beans>

当使用JPA自动建表时,会在Spring主配置文件applicationContext.xml中添加“<import resource=“springJpa/springJpa.xml”/>”。

LocalContainerEntityManagerFactoryBean的packagesToScan属性,支持指定单个或多个Entity类所在包,其他形式的设置如下所示:

<property name="packagesToScan" value="adrninistrator.test_jpa.entity"/>
<property name="packagesToScan">
	<value>adrninistrator.test_jpa.entity, adrninistrator.test_jpa.entity2</value>
</property>

JPA属性支持通过jpaProperties、jpaPropertyMap属性进行其他形式的设置,如下所示:

<property name="jpaProperties">
	<props>
		<prop key="hibernate.hbm2ddl.auto">update</prop>
		<prop key="hibernate.show_sql">true</prop>
		<prop key="hibernate.format_sql">true</prop>
	</props>
</property>
<property name="jpaPropertyMap">
	<map>
		<entry key="hibernate.hbm2ddl.auto" value="update"/>
		<entry key="hibernate.show_sql" value="true"/>
		<entry key="hibernate.format_sql" value="true"/>
	</map>
</property>

1.3.3. H2数据库连接参数

当使用JPA自动建表时,在H2数据库的连接参数中,不再需要通过INIT参数指定创建数据库表的SQL脚本信息。

1.3.3.1. 使用H2嵌入(本地)模式

当使用H2数据库嵌入(本地)模式与JPA自动建表时,可参考示例项目unit_test_config.groovy文件中的use_h2_file_jpa元素。

在XML文件中指定的数据库连接URL参数示例如下:

jdbc:h2:file:./build/h2db;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;INIT=CREATE SCHEMA IF NOT EXISTS TEST\;SET SCHEMA TEST"

以上创建并设置SCHEMA是为了使生成的H2数据库文件能够使用数据库工具打开。

在properties文件中指定时,反斜杠需要转义为两个反斜杠“\\”;在Groovy配置文件中指定时,反斜杠需要转义为四个反斜杠“\\\\”。

1.3.3.2. 使用H2内存数据库模式

当使用H2内存数据库模式与JPA自动建表时,可参考示例项目unit_test_config.groovy文件中的use_h2_mem_jpa元素,数据库连接URL参数示例如下:

jdbc:h2:mem:;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE

1.4. JPA自动建表的时间类型

使用MySQL数据库表生成Entity类时,时间类型字段在Entity类中对应的类型使用java.sql.Timestamp。

使用JPA自动建表时,Entity类中的Timestamp类型的字段,在MySQL中创建的数据库表字段类型为datetime,不包含小数秒精度(即使MySQL原始数据库中对应字段包含);在H2中创建的数据库表字段类型为timestamp。

参考 https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html ,MySQL的时间类型的小数秒精度默认值为0(与标准SQL的默认值6不同),即时间数据的最小精度为秒。需要注意可能导致时间数据精度与预期不相符,导致更新时返回的受影响行数改变。

参考 http://h2database.com/html/datatypes.html#timestamp_type , H2的timestamp类型的小数秒精度默认值为6,即时间数据的最小精度比秒更小。

1.5. 指定JPA自动建表的字段定义

参考 https://docs.jboss.org/hibernate/jpa/2.2/api/javax/persistence/Column.html#columnDefinition-- 。

Entity类中的@Column注解的columnDefinition属性,可以指定生成列的DDL时使用的SQL片段。

通过Entity类中的@Column注解的columnDefinition属性,可以指定创建数据库表时的对应字段的类型、非空属性、默认值、注释等字段定义,会覆盖Entity类对应字段的类型,及@Column中的length、nullable、precision、scale等属性对于字段的设置。

可参考示例项目TestTableOther类,在JPA自动建表时,创建的数据库表的字段定义与columnDefinition属性一致。

Entity类中的@Column注解的columnDefinition属性示例如下:

@Column(name = "\"flag\"", columnDefinition = "varchar(32) default 'test' COMMENT 'flag'")
private String flag;

columnDefinition属性可以准确指定数据库字段的定义,但不同数据库的语句细节可能存在差异,因此在根据数据库表生成JPA Entity类时,未使用columnDefinition属性。数据库字段的默认值只能通过columnDefinition属性指定,当需要使用数据库字段的默认值时,需要单独处理。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a82514921/article/details/108041847

智能推荐

promise.all和promise.race的应用场景并举例说明-程序员宅基地

文章浏览阅读5.8k次,点赞4次,收藏12次。问题描述为了解决前端异步函数多层嵌套会产生回调地狱问题,以及回调地狱错误不方便捕捉的问题。那些制造规则的大佬们,就在ES6中加入了一个新功能~Promise。Promise.all接收的是数组,得到的结果也是数组,并且一一对应,也可以理解为Promise.all照顾跑的最慢的,最慢的跑完才结束。Promise.race接收的也是数组,不过,得到的却是数组中跑的最快的那个,当最快的一跑完就立马结束。Promise.all方法Promise.all( ).then( )适用于处理多个异步_promise.all和promise.race

RabbitMQ 虚拟机/用户/权限设置_rabbitmq自己添加虚拟机如何使用-程序员宅基地

文章浏览阅读3.7k次。RabbitMQ 虚拟机/用户/权限设置环境:操作系统:Windows 10 Erlang版本号:21.0.1 RabbitMQ版本号:3.7.12(1) rabbitmq-server.bat启动服务。 (2) 进入RabbitMQ安装目录D:\Program Files\RabbitMQ\Server\rabbitmq_server-3.7.12\sbin 进行命令行操作。 注:无需通过命令行连接RabbitMQ服务,启动服..._rabbitmq自己添加虚拟机如何使用

华硕天选笔记本电脑启动机器后搜索不到网络_天选笔记本电脑连接不到网络-程序员宅基地

文章浏览阅读9.4k次,点赞4次,收藏17次。华硕笔记本电脑启动机器后搜索不到网络问题华硕天选笔记本电脑启动机器后搜索不到网络,一个月要出现几次,有时候重启就好了,有时候重启了也不行解决开始->设置->网络和internet->网络重置->立即重置 电脑会在5分钟之后自动重启..._天选笔记本电脑连接不到网络

PHP最新版本及比较_php 最新版本-程序员宅基地

文章浏览阅读1.7w次。php8PHP8,新的主要PHP版本,预计将在2020年12月3日发布。PHP 5.62018年12月,对PHP5.6的社区支持结束php72015年6月11日,正式公开发布PHP7第一版的alpha版本。2022年11月28结束支持为什么么开发团队应该将 PHP 5.6 升级到 7PHP升级的障碍:公司说不许多公司认为PHP升级的成本太高。这些受访者认为,他们需要重写其整个代码库,这将搁置关键项目。推高开发成本导致因等待新功能而感到沮丧的客户这是.._php 最新版本

Auto.js Run ReferenceError: “activity“ is not defined. (file:///android_asset/modules/__ui__.js#98)_鈥渁ctivity鈥漣s not defined-程序员宅基地

文章浏览阅读3.1k次。Auto.js Run ReferenceError: "activity" is not defined. (file:///android_asset/modules/__ui__.js#98)报错信息10:16:27.901/E: ReferenceError: "activity" is not defined. (file:///android_asset/modules/__ui__.js#98)ReferenceError: "activity" is not defined. _鈥渁ctivity鈥漣s not defined

Java获取某个月的天数_java编程判断某月有多少天-程序员宅基地

文章浏览阅读6w次,点赞32次,收藏34次。不同的月可能有不同的天数, 有的是30天, 有的是31天, 对于二月的天数判断还得先判断是平年还是闰年, 所以如果自己写代码判断会比较麻烦, 其实java.util.Calendar中已经提供了获取天数的方法, 代码如下:package top.itart;import java.text.ParseException;import java.text.SimpleDateFor_java编程判断某月有多少天

随便推点

一文读懂RFID标签和读写器_rfid读写 csdn-程序员宅基地

文章浏览阅读7.6k次,点赞4次,收藏25次。RFID标签和读写器介绍_rfid读写 csdn

php经典题,PHP经典面试题集锦-程序员宅基地

文章浏览阅读81次。本文较为详细的分析了PHP经典面试题。。具体如下:做了一下网络上的php题目,不知不觉做到现在.....把答案贴出来,供参考之用。1、用PHP打印出前一天的时间格式是2006-5-10 22:21:21(2分)$a = date("Y-m-d H:i:s", strtotime("-1 day"));print_r($a);2、echo(),print(),print_r()的区别(3分)echo..._php评价题

SQLServer CDC实现数据变更捕获_sqlserver cdc 捕获时间-程序员宅基地

文章浏览阅读4.9k次。在SQL Server2008之前,对数据变更的捕获通常使用触发器、时间戳等低效高成本的功能来实现,所以很多系统都没有做数据变更或者仅仅对核心表做监控。有了CDC, 则查看数据变更捕获就一目了然了(包括DDL的变更)。一直很想写一篇关于CDC的文章, 网上的也够多了, 但我这篇重在测试其实用性吧。_sqlserver cdc 捕获时间

C/C++《数据结构大作业》[2023-10-01]-程序员宅基地

文章浏览阅读23次。要求一、作业目的1、 掌握用数据结构的知识进行程序设计。2、 应用所学的数据结构完成一个具有一定实际意义的应用程序的设计、编码、调试,锻炼实践动手能力,提高编程水平。二、作业内容。

Cadence Virtuoso IC618 AC仿真测量电容_virtuoso 测mos 电容-程序员宅基地

文章浏览阅读5k次,点赞7次,收藏49次。Cadence Virtuoso IC618 AC仿真测量电容的基本原理是利用电容的阻抗计算公式,仿真并测量流过电容的电流值,通过设置合适的频率以及交流电压值,使得电流值和被测电容在数值上相等。_virtuoso 测mos 电容

Mac状态栏图标如何自定义排序?_苹果电脑邮箱已发送怎么按时间排序-程序员宅基地

文章浏览阅读3k次。最近遇到一个苦恼。就是搜狗输入法的输入状态栏总是在状态栏的最左侧,但是这会经常造成在使用某些应用时,被其他应用的状态栏遮盖的情况。解决方法是:按住command键,然后就可以用鼠标进行拖动自定义了,简直太强!参考文献:Mac 上的菜单栏包含哪些项?..._苹果电脑邮箱已发送怎么按时间排序