转载:http://www.ibm.com/developerworks/cn/java/j-lo-hibernate3/
Hibernate 作为 Java ORM 模式的优秀开源实现, 当下已经成为一种标准,为饱受 JDBC 折磨的 Java 开发者带来了“福音。快速的版本更新,想开发者所想,Hibernate 的开发团队俨然就是我们开发者的知音呀。随着 Hibernate 的用户群的越来越壮大,Hibernate 的功能也变得更加强大和健硕起来,下面就对于我们比较常用和关心的一些内容做一些比较深入的探讨,我们的宗旨就是不但会灵活应用,还能知其所以然,不要求大家一定要把 Hibernate 的原理弄的很清楚,但其中一些好的模式,好的设计方法及其中重要功能的实现原理和方法还是对我们很有帮助的。我们将会从 Hibernate 的对象关系映射,Hibernate 的事务处理,Hibernate 对大数量的处理方法以及 Hibernate 根据不同情况怎样来调整性能等方面来和大家共同探讨。下面我们开始讲解 Hibernate 的对象关系映射。
深度探索一(Hibernate 的对象关系映射)
首先我们新建一个 Java project,命名为 hibernate-deep-research。我们知道现在通过数据表反生成的 Java 对象的工具很多,比如 Jboss Tools 的 HibernateTools 等,选择你熟悉的就好了,都大同小异的,为了更好的掌握基本知识,本文没使用这些工具, 第一步我们首先完成 Hibernate 的配置文件 - hibernate.cfg.xml,, 该文件内容见清单 1 所示:
清单 1.hibernate.cfg.xml 内容
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="sessionFactory"> <property name="hibernate.bytecode.use_reflection_optimizer">false</property> <property name="hibernate.connection.driver_class">org.h2.Driver</property> <property name="hibernate.connection.url">jdbc:h2:~/test</property> <property name="hibernate.connection.username">sa</property> <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property> <mapping class="org.ibm.hibernate.deep.research.Test" /> </session-factory> </hibernate-configuration>
从这个 Hibernate 的配置文件中我们可以看出本文使用的数据库为 H2,所以我们要将 H2 的 jar 包引到本工程中。关于 H2 的使用方法,这里不做详细介绍了,它是 HSQLDB 的重写,速度更快些。我们还需要一个 POJO 对象类 Test,值得注意的是我们这里 mapping 属性设置的是 class 而不是 resource,如果是 resource 我们就需要指定 hbm 的 xml 文件,下面我们看下 Test 这个类,POJO Test 类的详细代码见清单 2 所示:
清单 2.Test 对象类内容
@Entity @Table(name = "TEST", schema = "PUBLIC", catalog = "TEST") public class Test implements java.io.Serializable { private int id;private String name; public Test() {} public Test(int id) {this.id = id;} public Test(int id, String name) { this.id = id; this.name = name;} @Id @Column(name = "ID", unique = true, nullable = false) public int getId() { return this.id;} public void setId(int id) { this.id = id;} @Column(name = "NAME", length = 10) public String getName() { return this.name;} public void setName(String name) { this.name = name;} }
Test 这个 POJO 类我们使用 annotation 来完成与数据表的映射关系,@Entity 表示这是一个实体类,@Table 指定与那个数据表产生映射关系,@Id 指明主键,@Column 来指明 POJO 对象中的变量与数据表中字段的对应关系,当然 annotation 还有很多,这里就不一一介绍了。从中我们可以知道 Test 这个 POJO 类与数据库中的 test 表产生映射关系,那么这样的映射关系 Hibernate 是怎样来维护的呢?还有上面的 Hibernate 配置文件 hibernate.cfg.xml 又是什么时候,怎样加载的呢?配置文件中的 mapping 属性有的是 resource,有的是 class,Hibernate 又是怎么来区分它们的呢? resource 与 class 加载的不同点又在什么地方呢 ? 如果能回答这些问题,你就基本了解了 Hibernate 的对象映射关系,你可以跳过这部分了,呵呵,如果你还没有个明确答案,那么请继续,下面我们就通过一个测试来一一解答上面的这些疑问。新建一个单元测试类命名为 HibernateTestCase, 继承自 TestCase,下面我们来看下 HibernateTestCase 的 setUp 方法,代码见清单 3 所示:
清单 3.HibernateTestCase 代码
Transaction tx; protected void setUp() throws Exception { Configuration cfg = new Configuration(); cfg.configure("/org/hibernate.cfg.xml"); SessionFactory sf = cfg.buildSessionFactory(); session = sf.openSession(); tx = session.beginTransaction(); }
然后我们执行这个测试用例,跟踪下执行过程,我们会发现虽然在创建 configration 实例时我们没有指定任何资源文件,但 Hibernate 会自动设置 hibernate.properties 为默认加载文件,Hibernate 是在哪里又是怎样来设置的呢?我们来看下 Environment 这个类,在这个类的第 608 行有这么段代码 ConfigHelper.getResourceAsStream("/hibernate.properties"),这段代码是被 Configration 类的 reset 方法调用的,我们回过头来再看下 Environment 中的这段代码,如清单 4 所示:
清单 4.Environment 中的代码
ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_NONE), "NONE" ); ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_READ_UNCOMMITTED), "READ_UNCOMMITTED" ); ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_READ_COMMITTED), "READ_COMMITTED" ); ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_REPEATABLE_READ), "REPEATABLE_READ" ); ISOLATION_LEVELS.put( new Integer(Connection.TRANSACTION_SERIALIZABLE), "SERIALIZABLE" );
这段代码是初始化事务隔离级别的,我们在讲到事务那一节会用到,在这里先简单提一下,有个印象。
我们接下来再看下 Hibernate 是怎样加载我们指定的配置文件的,来看下 ConfigHelper 这个类的 getResourceAsStream 方法,见清单 5 所示:
清单 5.getResourceAsStream 方法
public static InputStream getResourceAsStream(String resource) { String stripped = resource.startsWith("/") ? resource.substring(1) : resource; InputStream stream = null; ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader!=null) { stream = classLoader.getResourceAsStream( stripped );} if ( stream == null ) {stream = Environment.class.getResourceAsStream( resource );} if ( stream == null ) {stream = Environment.class.getClassLoader().getResourceAsStream( stripped );} if ( stream == null ) {throw new HibernateException( resource + " not found" );} return stream;}
首先我们看下这个方法的第一行,它的作用是去掉传进来参数的第一个”/”, 为什么要去掉呢,大家发现没有 Hibernate 在指定默认文件时,用的方式是 ConfigHelper.getResourceAsStream("/hibernate.properties"),默认也要加上”/”, 怎么总感觉 Hibernate 有点自虐倾向,呵呵,那么 Hibernate 为什么要去掉这个”/”, 我们在看下清单 5,代码中是通过 ClassLoader 来处理资源文件的,对于 Class 和 ClassLoader 加载资源文件的区别,我想各位一定清楚吧,Class 处理资源文件前面是可以带”/”的,而通过 ClassLoader 处理资源文件前面是不能有”/”, 否则将永远找不到文件。接下来我们来看下 configration 这个类中的 parseMappingElement 方法,代码见清单 6 所示:
清单 6.parseMappingElement
private void parseMappingElement(Element mappingElement, String name) { final Attribute resourceAttribute=mappingElement.attribute("resource" ); final Attribute fileAttribute = mappingElement.attribute( "file" ); final Attribute jarAttribute = mappingElement.attribute( "jar" ); final Attribute packageAttribute = mappingElement.attribute( "package" ); final Attribute classAttribute = mappingElement.attribute( "class" ); if ( resourceAttribute != null ) { final String resourceName = resourceAttribute.getValue(); log.debug( " session-factory config [{}] named resource [{}] for mapping", name, resourceName ); addResource( resourceName );} else if ( fileAttribute != null ) {final String fileName = fileAttribute.getValue(); log.debug( " session-factory config [{}] named file [{}] for mapping", name, fileName ); addFile( fileName );} else if ( jarAttribute != null ) {final String jarFileName = jarAttribute.getValue(); log.debug( " session-factory config [{}] named jar file [{}] for mapping", name, jarFileName ); addJar( new File( jarFileName ) ); }else if ( packageAttribute != null ) { final String packageName = packageAttribute.getValue(); log.debug( " session-factory config [{}] named package [{}] for mapping", name, packageName ); addPackage( packageName );} else if ( classAttribute != null ) { final String className = classAttribute.getValue(); log.debug( " session-factory config [{}] named class [{}] for mapping", name, className ); try {addAnnotatedClass( ReflectHelper.classForName( className ) );} catch ( Exception e ) {throw new MappingException( "Unable to load class [ " + className + "] declared in Hibernate configuration <mapping/> entry",
这个方法是被 parseSessionFactory 方法调用,调用语句见清单 7 所示:
清单 7. 调用 parseMappingElement 代码块
if ( "mapping".equals( subelementName ) ) { parseMappingElement( subelement, name ); }
我们再来看下清单 6 中的代码,通过代码我们知道 mapping 支持的属性类型有五种,分别是 resource,file,jar,package 和 class,当属性是 class 时候会调用 addAnnotatedClass 方法将该 Class 加载,并放入 List 中。当然其它的三种方式也会执行不同的操作的,这里建议应该把判断 class 这个条件提到 resource 的后边,性能会更好一些。至此 Hibernate 加载资源文件及 POJO 与数据表的映射关系我们就讲完了,我们知道映射关系中有好多属性,只要你根据以上这个思路去跟踪 Hibernate 的执行过程,一切都会明白的,我们在这里就不一一介绍了。下面我们开始讲解关于 Hibernate 事务的一些知识。
深度探索二(Hibernate 的事务管理)
我们知道 Hiberante 是对 JDBC 的轻量级封装,Hiberante 本身并不具备事务管理能力,
它是将事务的管理委托给底层的 JDBC 或 JTA 来实现事物的管理和调度的。也就是说 Hibernate 支持的事务类型有这么两种 JDBC 和 JTA, 那么这两种事务之间又有什么区别呢? Hibernate 的 JDBC 事务是基于 JDBC Connection 实现的,它的生命周期是在 Connection 之内的,也就是说 Hibernate 的 JDBC 事务是不能跨 Connection 的。而 Hibernate 的 JTA 事务类型是由 JTA 容器来管理的,JTA 容器对当前加入事务的众多 Connection 进行调度,实现其事务性要求。JTA 的事务周期可横跨多个 JDBC Connection 生命周期。了解了 Hibernate 的事务类型后,我们再来跟踪下 Hibernate 是怎样来实现这两种事务类型的,下面我们就来讲解下 Hibernate 是怎样来实现 JDBC 事务管理的。看下清单 3 中的最后第二行代码 session = sf.openSession(),在 open Session 时候 Hibernate 都做了些什么呢?它首先调用 SessionFactoryImpl 的 openSession 方法,在 openSession 方法中会获得 connection 连接,相当于 JDBC 中的 getConnection(), 然后设置了 AutoCommit 为 false,设置代码见清单 8 所示:
清单 8.SessionImpl 部分代码
SessionImpl( final Connection connection, final SessionFactoryImpl factory, final boolean autoclose, final long timestamp, final Interceptor interceptor, final EntityMode entityMode, final boolean flushBeforeCompletionEnabled, final boolean autoCloseSessionEnabled, final ConnectionReleaseMode connectionReleaseMode) { super( factory ); this.rootSession = null; this.timestamp = timestamp; this.entityMode = entityMode; this.interceptor = interceptor; this.listeners = factory.getEventListeners(); this.actionQueue = new ActionQueue( this ); this.persistenceContext = new StatefulPersistenceContext( this ); this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; this.autoCloseSessionEnabled = autoCloseSessionEnabled; this.connectionReleaseMode = connectionReleaseMode; this.jdbcContext = new JDBCContext( this, connection, interceptor ); loadQueryInfluencers = new LoadQueryInfluencers( factory ); if ( factory.getStatistics().isStatisticsEnabled() ) { factory.getStatisticsImplementor().openSession();} if ( log.isDebugEnabled() ) { log.debug( "opened session at timestamp: " + timestamp );}}
autoclose 传过来的值是 false,其实这个值是在 Settings 这个类中设置的。然后我们再来看下清单 3 中的最后一行代码 tx = session.beginTransaction() 这行代码,首先调用的是 SessionImpl 这个类的 beginTransaction 方法,代码见清单 9 所示:
清单 9.beginTransaction 代码段
errorIfClosed(); if ( rootSession != null ) { // todo : should seriously consider not allowing a txn to begin from a child session // can always route the request to the root session... log.warn( "Transaction started on non-root session" ); } Transaction result = getTransaction(); result.begin(); return result;
我们主要看下最后面的第三行和第四行代码,Transaction result = getTransaction() 我们可以看到,result 为 org.hibernate.transaction.JDBCTransaction,那么 result.begin() 调用的就是 JDBCTransaction 中的 begin 方法,这里就不列出方法代码了,这个方法的主要功能就是再一次检查一下 AutoCommit 是否为 false,如果不是就设置成 false,可以看到 Hibernate 在 openSession 和 begin transaction 中都需要检查事务是否是 auto commit 的。然后会调用 DriverManagerConnectionProvider 的 getConnection 方法,方法代码见清单 10 所示:
清单 10.getConnection 方法体
public Connection getConnection() throws SQLException { if ( log.isTraceEnabled() ) log.trace( " total checked-out connections: " + checkedOut ); synchronized (pool) { if ( !pool.isEmpty() ) { int last = pool.size() - 1; if ( log.isTraceEnabled() ) { log.trace("using pooled JDBC connection, pool size: " + last); checkedOut++;} Connection pooled = (Connection) pool.remove(last); if (isolation!=null) pooled.setTransactionIsolation(isolation.intValue() ); if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit); return pooled;}} log.debug("opening new JDBC connection"); Connection conn = DriverManager.getConnection(url, connectionProps); if (isolation!=null) conn.setTransactionIsolation( isolation.intValue() ); if ( conn.getAutoCommit()!=autocommit ) conn.setAutoCommit(autocommit); if ( log.isDebugEnabled() ) { log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );} if ( log.isTraceEnabled() ) checkedOut++;return conn;}
从这段代码中更能证明我们上面说的,Hibernate 只是对 JDBC 的封装,它本身不做任何额外的事情的,通过 DriverManager 来获得 connection 连接和 JDBC 一样,我们再来看下这段代码中的一个变量 Isolation,这个变量我们在清单 4 中提起过,是关于事务隔离级别的,还记得事务隔离级别都有那些吗?我们该如何设置事务隔离级别呢?目前这个例子没有设置事务隔离级别,所以 Isolation 的值为 null,我们再来看下清单 4 中的不同事务隔离级别都表示什么意思?
TRANSACTION_READ_UNCOMMITTED 表示可以读到未提交事物的数据,也就是常说的脏读;TRANSACTION_READ_COMMITTED 表示未提交事务之前数据库中读不到该记录;TRANSACTION_REPEATABLE_READ 表示此记录不能被修改,但可以读到已经添加的记录;TRANSACTION_SERIALIZABLE 表示所有情况都加锁,事务是一个接一个的串行执行的,保证不出现脏读,不可重复读,幻影等情况,但要付出很大代价,性能不好。那么 Hibernate 是怎样来设置隔离级别的呢?我们只需在 Hibernate 配置文件中添加 hibernate.connection.isolation 这个属性就可以,它的值是数值型的,可设置成 1,2,4,8 对应上面的介绍顺序。不同的数据库默认的隔离级别是不一样的,所以要根据不同的数据库来设置它所支持的数据库隔离级别。对于 JTA 事务类型大家根据讲解 JDBC 的方法可以自己去看看 Hibernate 是怎样实现的。下面我们我开始讲解下 Hibernate 对于大数据量是采用什么方式来处理的。
深度探索三(Hibernate 对大数据量的处理)
我们在项目中经常会发现一旦要访问的数据量达到一定数量级后,系统会变得异常的慢,这样的情况多数产生在批量操作中的,如果只是单纯地从用户操作界面发送的请求的话,这种情况基本不会发生的,除非你没有应用分页机制,下面我们就具体讲解下,对于这种批量的,大数据量该用什么方式来处理。现在有一个需求就是要求将年龄大于 40 岁的所有记录删除,这样的数据将会有 5 万条,通常的做法,应该像清单 11 那样:
清单 11. 菜鸟级的大数据量删除方式
Iterator it = session.createQuery(" from Employee where age >40").iterate(); while (it.hasNext()) { Employee employee = (Employee) it.next(); session.delete(employee); } tx.commit(); session.close();
我们会发现以上的操作 Hibernate 执行了大量的 SQL 语句,并将这些对象做了持久化,除了消耗大量内存外,执行起来还相当的慢,有的人说,我们可以用 evict 方法呀,每执行完一次删除后将内存中的持久化对象清理掉,不错,可以这么做,这样解决了消耗大量内存的问题,但是如果跟踪 Hibernate 执行过程的话,你会发现大量的 SQL 语句依然存在,那么我们有没有一种方法只执行一条语句就删除掉那 5 万多条记录呢?当然有,我们来看下 Hibernate3 给我提供的批量操作方法,修改后的代码见清单 12 所示:
清单 12.Hibernate3 提供的批量操作方法
int it = session.createQuery("delete Employee where age >40").executeUpdate();
这个方法,避免了上面提出的两个缺点,我们来看下 Hibernate 是怎样来实现这个功能的,看下 Hibernate 自带的 BasicExecutor 类的 execute 方法,方法体见清单 13 所示:
清单 13.BasicExecutor 的 execute 方法片段
st = session.getBatcher().prepareStatement( sql ); Iterator parameterSpecifications = this.parameterSpecifications.iterator(); int pos = 1; while ( parameterSpecifications.hasNext() ) { final ParameterSpecification paramSpec = ( ParameterSpecification ) parameterSpecifications.next(); pos += paramSpec.bind( st, parameters, session, pos );} if ( selection != null ) { if ( selection.getTimeout() != null ) {st.setQueryTimeout( selection.getTimeout().intValue() );}} return st.executeUpdate(); }
这段代码是不是有种似曾相识的感觉,呵呵,那说明你 JAVA 基础还可以,的确上面代码和我们最早用 JDBC API 来操作批量数据方式是一样的。
深度探索四(Hibernate 性能调优)
我们知道 Hibernate 3 去掉了 find 方法,之所以去掉也是考虑到性能问题。因为 find 方法对于缓存只写不读,性能低下,如果您有用到 Hibernate 3 以前的版本,要注意一下。
Hibernate 3 以前版本在普通情况下持久化对象时会把该对象的属性全都加载进来,即使有些大对象我们用不到。因为延迟加载属性只能作用在类级别,Hibernate 3 允许我们在属性级别上应用延迟加载功能,这样就可以有选择的加载对象的属性了。设置也很简单,只需在属性的 get 方法上加入 @Basic(fetch = FetchType.LAZY) 这行代码就可以了,然后我们需要增强该类,通过 Ant 脚本来加强就可,很简单,就不给出代码了,要不然加入的注释将被忽略。如果你使用 hbm 格式来映射文件的话,那么在属性行加入 lazy=true 即可。以上讲的是属性级别的延迟加载,类级别的延迟加载大家也要灵活应用,毕竟它对提升性能还是很有帮助的。
我们上面也提到了关于大数据量缓存的问题,提到对于那些不常用的数据要及时清理缓存,我们可以用 session 的 clear 或 evict 方法,养成好习惯,省着一旦出现性能瓶颈时盲目。对于监控性能的一些工具大家可以自己研究一下,比如 loadrunner 等都是很不错的。
相关推荐
《Hibernate注解与Hibernate3深度解析》 在Java开发领域,Hibernate作为一种强大的对象关系映射(ORM)框架,极大地简化了数据库操作。本篇将深入探讨Hibernate 3版本中的注解使用,帮助开发者理解如何利用注解进行...
总结,通过对Hibernate源码的深度解析,我们可以更深刻地理解ORM的工作机制,这对于优化数据库操作、解决性能问题以及调试代码都大有裨益。在实践中,这种深入的理解能帮助开发者编写出更高效、更稳定的代码,提升...
这里,我们将深度解析这个主题,探讨在Java环境下构建游戏服务器的关键知识点。 首先,我们需要理解Java语言的优势。Java以其跨平台的特性、丰富的类库以及强大的性能,成为了后端开发的首选语言之一,尤其适合大型...
《Hibernate3:注解与Commons Annotations的深度解析》 Hibernate3是一款强大的Java持久化框架,它极大地简化了数据库操作,使得开发者可以专注于业务逻辑,而不是底层的数据访问细节。本篇将深入探讨Hibernate3中...
《Hibernate3:持久化框架深度解析》 Hibernate3是一款强大的Java对象关系映射(ORM)框架,它在Java开发领域中扮演着至关重要的角色。这个名为"hibernate3.zip"的压缩包文件包含了关于Hibernate3的所有核心组件、...
《Hibernate与Middlegen-Hibernate-r5:数据库持久化框架深度解析》 在Java开发领域,Hibernate是一个广泛应用的开源对象关系映射(ORM)框架,它简化了数据库操作,使得开发者能够以面向对象的方式处理数据库交互...
5. **Hibernate深度解析**:这应该是对Hibernate框架内部机制的详细分析,包括缓存机制、二级缓存、查询优化策略等,帮助开发者理解和解决复杂的数据访问问题。 6. **OGNL深度解析**:Object-Graph Navigation ...
《Hibernate技术深度解析:中文文档与实战指南》 在Java世界中,Hibernate作为一个强大的对象关系映射(ORM)框架,极大地简化了数据库操作。本文将深入探讨Hibernate的核心概念,结合提供的中文文档,以及...
《跟开涛学Spring3(深度解析Spring3)》是一本专为开发者设计的中文教程,旨在帮助读者深入理解Spring3框架的核心概念和技术。Spring框架是Java开发中的一个基石,尤其在企业级应用中占据着举足轻重的地位。通过...
《Hibernate框架深度解析——基于黑马程序员2016版教学资料》 Hibernate,作为一个强大的对象关系映射(ORM)框架,极大地简化了Java开发者在数据库操作中的工作。它通过提供数据持久化的对象模型,使得开发者可以...
**Hibernate API 深度解析** Hibernate 是一个强大的对象关系映射(ORM)框架,它为Java开发者提供了方便的数据持久化服务。通过使用Hibernate API,开发者可以将数据库操作转化为对Java对象的操作,大大简化了...
《Hibernate Validator 深度解析:4.0.1.GA 版本详解》 Hibernate Validator,作为Java世界中的一款强大且广泛使用的验证框架,极大地简化了应用中的数据验证过程。本文将深入探讨 Hibernate Validator 4.0.1.GA ...
### Hibernate原理深度解析 #### Hibernate为何重要? Hibernate作为一款开源的对象关系映射(ORM)框架,在Java开发领域占据着举足轻重的地位。其重要性体现在以下几个方面: 1. **资源管理**:Hibernate通过...
本篇将从源码的角度,对Hibernate进行深度解析,帮助读者理解其核心机制。 一、Hibernate概览 Hibernate是一个开源的、基于Java的持久化框架,它提供了一种在Java应用和关系数据库之间建立映射的方法,使得开发者...
《Hibernate Validator 深度解析与应用实践》 Hibernate Validator 是一个基于 Java Bean Validation 规范的开源验证框架,它是 Hibernate 项目的一部分,主要用于在 Java 应用程序中实现数据校验。本篇文章将深入...
《Hibernate Validator 深度解析》 Hibernate Validator 是一个基于 Bean Validation 规范的实现,是 Hibernate 项目的一部分,主要用于进行 Java 对象的验证。它提供了丰富的约束注解和自定义验证逻辑,使得开发者...
《Hibernate技术深度解析》 Hibernate,作为Java领域中的一款强大且广泛应用的对象关系映射(ORM)框架,极大地简化了数据库操作。它允许开发者用面向对象的方式处理数据,从而避免了传统SQL语句的手动编写,提高了...
本文将围绕Hibernate3的源码进行深度剖析,帮助读者理解其核心机制和设计思想。 一、Hibernate3概述 Hibernate3是Java开发中用于数据库操作的开源框架,它简化了数据库访问,通过提供一种对象-关系映射(ORM)工具...
本资源包含了Hibernate的深度解析、全套开发视频教程以及源码和相关开发文档,是学习和精通Hibernate的理想资料。 首先,Hibernate的核心理念是将Java对象与数据库表进行映射,这样就无需编写大量的SQL语句,提高了...
《Hibernate Validator 深度解析与应用》 Hibernate Validator 是 Hibernate 社区提供的一款强大的Java Bean验证框架,它基于JSR-303(Bean Validation)标准,为开发者提供了便捷的验证API,使得数据验证过程更为...