构建基于 JPA 的 Hibernate 环境
来源:互联网 发布:mac抓取网页视频 编辑:程序博客网 时间:2024/06/05 00:07
——跟我一起学 Hibernate 系列(2)
1. 主要的开发环境
- Maven 3.3.9
- idea 14.1.1
- Bitronix 2.1.3(JTA 事务)
2. pom.xml
- 所有的依赖包由 Maven 统一管理
- 跟我一起学 Hibernate 系列中所有的特性展示,都基于这次构建的开发环境
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <!-- JPA 标准 API--> <hibernate.jpa21.api.version>1.0.0.Final</hibernate.jpa21.api.version> <!-- Hibernate 实现--> <hibernate.version>5.1.0.Final</hibernate.version> <!-- Bean 验证器 标准 API --> <validation.api.version>1.1.0.Final</validation.api.version> <!-- Hibernate 验证器实现--> <hibernate.validator.version>5.2.1.Final</hibernate.validator.version> <javax-el.version>3.0.1-b04</javax-el.version> <!-- 日志--> <slf4j.impl.version>1.6.1</slf4j.impl.version> <!-- TestNG 单元测试--> <testing.version>6.8.7</testing.version> <!-- Jav SE 环境下使用 Bitronix (为JTA 事务管理器提供数据库连接池)--> <btm.version>2.1.3</btm.version> </properties> <!-- 依赖库--> <dependencies> <!-- TestNG 单元测试--> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testing.version}</version> <exclusions> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency> <!-- slf4j 日志--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>${slf4j.impl.version}</version> </dependency> <!-- Bitronix 数据库连接池 --> <dependency> <groupId>org.codehaus.btm</groupId> <artifactId>btm</artifactId> <version>${btm.version}</version> </dependency> <!-- Hibernate(JPA实现)--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <!-- Bean 验证器 API 与实现--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate.validator.version}</version> </dependency> <!-- EL --> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>${javax-el.version}</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>${javax-el.version}</version> </dependency> <!-- Hibernate 审计--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> <version>${hibernate.version}</version> </dependency> <!-- EHCache 作为二级缓存--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>${hibernate.version}</version> </dependency> <!-- mysql driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> </dependencies>
3. 开发环境基础类
- 这些类都放在 env 包中
3.1 数据库产品类
package net.deniro.hibernate.env;import bitronix.tm.resource.jdbc.PoolingDataSource;import java.util.Properties;/** * * 数据库产品(目前只支持 MYSQL) * * @author Deniro Li * 2017/1/13 */public enum DatabaseProduct { MYSQL( new DataSourceConfiguration() { @Override public void configure(PoolingDataSource ds, String connectionURL) { ds.setClassName("bitronix.tm.resource.jdbc.lrc.LrcXADataSource"); ds.getDriverProperties().put( "url", connectionURL != null ? connectionURL : "jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull" ); Properties dp=ds.getDriverProperties(); dp.put("driverClassName", "com.mysql.jdbc.Driver"); dp.put("user","root"); dp.put("password",""); ds.setDriverProperties(dp); } }, //MySQL57InnoDBDialect 可用于 MySQL5.6 org.hibernate.dialect.MySQL57InnoDBDialect.class.getName() ); public DataSourceConfiguration configuration; public String hibernateDialect; private DatabaseProduct(DataSourceConfiguration configuration, String hibernateDialect) { this.configuration = configuration; this.hibernateDialect = hibernateDialect; } public interface DataSourceConfiguration { void configure(PoolingDataSource ds, String connectionURL); }}
3.2 使用 Bitronix 作为数据库事务
package net.deniro.hibernate.env;import bitronix.tm.TransactionManagerServices;import bitronix.tm.resource.jdbc.PoolingDataSource;import javax.naming.Context;import javax.naming.InitialContext;import javax.sql.DataSource;import javax.transaction.Status;import javax.transaction.SystemException;import javax.transaction.UserTransaction;import java.util.logging.Logger;/** * 使用 Bitronix 作为数据库事务 * * @author Deniro Li * 2017/1/13 */public class TransactionManagerSetup { public static final String DATASOURCE_NAME = "deniroDS"; private static final Logger logger = Logger.getLogger(TransactionManagerSetup.class .getName()); protected final Context context = new InitialContext(); protected final PoolingDataSource dataSource; public final DatabaseProduct databaseProduct; public TransactionManagerSetup(DatabaseProduct databaseProduct) throws Exception { this(databaseProduct, null); } public TransactionManagerSetup(DatabaseProduct databaseProduct, String connectionURL) throws Exception { logger.fine("启动数据库连接池"); logger.fine("为事务设置一个稳定的唯一标识"); TransactionManagerServices.getConfiguration().setServerId("deniroServer1"); logger.fine("关闭 JMX(为了单元测试方便)"); TransactionManagerServices.getConfiguration().setDisableJmx(true); logger.fine("关闭事务日志(为了单元测试方便)"); TransactionManagerServices.getConfiguration().setJournal(null); logger.fine("关闭在一个事务中无法获取数据库连接的警告信息"); TransactionManagerServices.getConfiguration().setWarnAboutZeroResourceTransaction (false); logger.fine("创建数据库连接池"); dataSource = new PoolingDataSource(); dataSource.setUniqueName(DATASOURCE_NAME); dataSource.setMinPoolSize(1); dataSource.setMaxPoolSize(5); dataSource.setPreparedStatementCacheSize(10); // 这里明确指定事务隔离级别,为了后面的高级特性展示 dataSource.setIsolationLevel("READ_COMMITTED"); //当 EntityManager 被挂起或者没有被加入事务的情况下,允许事务自动提交 dataSource.setAllowLocalTransactions(true); logger.info("选定的数据库是:" + databaseProduct); this.databaseProduct = databaseProduct; databaseProduct.configuration.configure(dataSource, connectionURL); logger.fine("初始化事务与资源管理器"); dataSource.init(); } public Context getNamingContext() { return context; } public UserTransaction getUserTransaction() { try { return (UserTransaction) getNamingContext().lookup("java:comp/UserTransaction"); } catch (Exception ex) { throw new RuntimeException(ex); } } public DataSource getDataSource() { try { return (DataSource) getNamingContext().lookup(DATASOURCE_NAME); } catch (Exception e) { throw new RuntimeException(e); } } public void rollback() { UserTransaction tx = getUserTransaction(); try { if (tx.getStatus() == Status.STATUS_ACTIVE || tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) tx.rollback(); } catch (SystemException e) { System.err.print("事务回滚失败!"); e.printStackTrace(System.err); } } public void stop() throws Exception { logger.fine("关闭数据库连接池"); dataSource.close(); TransactionManagerServices.getTransactionManager().shutdown(); }}
3.3 JNDI 配置
- 底层的 Bitronix 是使用 JNDI 来创建数据库连接池的
- 文件路径在 /resources 下
# Bitronix 内建了一个 JNDI contgext,所以这里直接绑定对应的类就好java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory
3.4 单元测试基础类
- 所有的 Hibernatge 单元测试都继承这个类
package net.deniro.hibernate.env;import org.testng.annotations.AfterSuite;import org.testng.annotations.BeforeSuite;import org.testng.annotations.Optional;import org.testng.annotations.Parameters;import java.util.Locale;/** * 在一个单元测试中,开启或关闭事务管理器或者数据库连接池 * * * @author Deniro Li * 2017/1/13 */public class TransactionManagerTest { //Static single database connection manager per test suite static public TransactionManagerSetup TM; @Parameters({"database", "connectionURL"}) @BeforeSuite public void beforeSuite(@Optional String database, @Optional String connectionURL) throws Exception { TM = new TransactionManagerSetup(database != null ? DatabaseProduct.valueOf(database .toUpperCase(Locale.CHINESE)) : DatabaseProduct.MYSQL, connectionURL); } @AfterSuite(alwaysRun = true) public void afterSuite() throws Exception { if (TM != null) TM.stop(); }}
4 基于 JPA 的 HelloWorld
4.1 POJO 类
package net.deniro.hibernate.model.helloworld;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;/** * @author Deniro Li * 2017/1/13 */@Entitypublic class Message { @Id @GeneratedValue//自动生成 ID private Long id; private String text; public String getText() { return text; } public void setText(String text) { this.text = text; }}
4.2 配置持久层单元
- 在 resources/META-INF/persistence.xml 下
- POJO 对应的表,Hibernate 会自动建立
<?xml version="1.0" encoding="UTF-8"?><persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence_2_1.xsd"> <!-- 配置持久层单元--> <!-- 每个配置文件至少配一个持久层单元;每个持久层单元的名字必须唯一--> <persistence-unit name="HelloWorldPU"> <!-- 数据源--> <jta-data-source>deniroDS</jta-data-source> <!-- 需要持久化的类--> <class>net.deniro.hibernate.model.helloworld.Message</class> <!-- 是否扫描 classpath 路径下的映射类,并自动加入这个持久层单元--> <exclude-unlisted-classes>true</exclude-unlisted-classes> <!-- 设置属性--> <properties> <!-- 删除并重建数据库(schema) --> <!-- 这个属性设置后,当 JPA 引擎启动时会删除并重建数据库--> <!-- 一般用于项目的自动化测试,因为测试需要一个干净的数据库环境--> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> <!-- 格式化输出 SQL(如果有输出日志)--> <property name="hiberate.format_sql" value="true"/> <!-- 输出因果链(如果有输出日志)--> <property name="hibernate.use_sql_comments" value="true"/> </properties> </persistence-unit></persistence>
4.3 单元测试
package net.deniro.hibernate.example.helloworld;import net.deniro.hibernate.env.TransactionManagerTest;import net.deniro.hibernate.model.helloworld.Message;import org.testng.annotations.Test;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.Persistence;import javax.transaction.UserTransaction;import java.util.List;import static org.testng.AssertJUnit.assertEquals;/** * 基于 JPA 的 HelloWorld * * @author Deniro Li * 2017/1/13 */public class HelloWorldJPA extends TransactionManagerTest { @Test public void storeLoadMessage() throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("HelloWorldPU"); try { { //保存 UserTransaction tx = TM.getUserTransaction(); tx.begin(); EntityManager em = emf.createEntityManager(); Message message = new Message(); message.setText("Hello World!"); em.persist(message); tx.commit(); em.close(); } { //查询 UserTransaction tx = TM.getUserTransaction(); tx.begin(); EntityManager em = emf.createEntityManager(); List<Message> messages = em.createQuery("select m from Message m") .getResultList(); assertEquals(messages.size(), 1); assertEquals(messages.get(0).getText(), "Hello World!"); //更新 messages.get(0).setText("Take me to your leader!"); tx.commit(); em.close(); } } finally { TM.rollback(); emf.close(); } }}
运行测试用例:
自此,我们基于 JPA 的 Hibernate 环境就搭建好啦 O(∩_∩)O~
0 0
- 构建基于 JPA 的 Hibernate 环境
- hibernate 基于JPA的事务管理
- 基于JPA的Hibernate->CRUD(简单应用)
- JPA hibernate 基于注解的级联
- 基于jpa/springData ,hibernate,mybtis的分页
- 基于hibernate 3.6的JPA的实现的bug
- 基于hibernate实现jpa规范
- 基于annotation的JPA和hibernate主键生成策略
- JPA 开发所需的Jar包 (基于Hibernate)
- JPA/Hibernate:基于版本的乐观锁并发控制
- JPA+Hibernate+Maven环境搭建
- 构建基于VIM的IDE环境
- 基于虚拟机的PC应用环境构建
- JSF+Spring+JPA(Hibernate实现)的环境搭建
- 一步步实现:JPA的基本增删改查CRUD(jpa基于hibernate)
- 为JPA和Hibernate构建巩固基础
- Hibernate,JPA 的关系。
- JPA核心API-基于Hibernate实现
- javamail 实现邮件发送(基于qq邮箱)
- D - Rectangles
- 联机Unity Profile性能调试技巧
- Apache Kafka笔记(一):基础架构
- javascript 笔记
- 构建基于 JPA 的 Hibernate 环境
- Leetcode-61. Rotate List
- selenium-java-Firefox 特殊异常:界面找不到元素
- 【通信框架】Google的开源通信框架protobuf概述
- [Codeforces734E]Anton and Tree 树的直径
- 《白说》---- 读书笔记
- spring中bean的生命周期详解
- vim各种命令
- Unity如何区分安卓、苹果设备是手机与平板?