Mkyong 中文博客翻译(八)

原文:Mkyong

协议:CC BY-NC-SA 4.0

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/Apache/commons/logging/log factory

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orgapachecommonslogginglogfactory/

一个常见的 Hibernate 错误,这是由于缺少依赖库——公共日志记录造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
	at org.hibernate.cfg.Configuration.<clinit>(Configuration.java:120)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 4 more 

解决办法

你可以在这里下载图书馆-http://commons.apache.org/logging/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.1.1</version>
      </dependency> 

hibernate外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById®;if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!‘undefined’){i[c]++} else{i[c]=1;} })(window, document, ‘InContent’, ‘script’, ‘mediaType’, ‘carambola_proxy’,‘Cbola_IC’,‘localStorage’,‘set’,‘get’,‘Item’,‘cbolaDt’,‘//web.archive.org/web/20190305140402/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0’)

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/dom4j/document exception

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orgdom4jdocumentexception/

一个常见的 Hibernate 错误,这是由于缺少依赖库 dom4j 造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/dom4j/DocumentException
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:17)
Caused by: java.lang.NoClassDefFoundError: org/dom4j/DocumentException
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 3 more 

解决办法

你可以在这里下载图书馆-http://sourceforge.net/projects/dom4j/files/dom4j/

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>dom4j</groupId>
		<artifactId>dom4j</artifactId>
		<version>1.6.1</version>
	</dependency> 

hibernate外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById®;if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!‘undefined’){i[c]++} else{i[c]=1;} })(window, document, ‘InContent’, ‘script’, ‘mediaType’, ‘carambola_proxy’,‘Cbola_IC’,‘localStorage’,‘set’,‘get’,‘Item’,‘cbolaDt’,‘//web.archive.org/web/20190301211220/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0’)

Hibernate 错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:org/hibernate/annotations/common/reflection/reflection manager

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-initial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-orghibernateannotationscommonreflectionreflectionmanager/

这是由于缺少 Hibernate commons 注释库造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: 
org/hibernate/annotations/common/reflection/ReflectionManager
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:19)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:11)
Caused by: java.lang.NoClassDefFoundError: org/hibernate/annotations/common/reflection/ReflectionManager
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.ReflectionManager
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 3 more 

解决办法

可以从 Hibernate 官网下载该库

或者

在 Maven 的 pom.xml 中添加依赖项

 <dependency>
		<groupId>hibernate-commons-annotations</groupId>
		<artifactId>hibernate-commons-annotations</artifactId>
		<version>3.0.0.GA</version>
	</dependency> 

页(page 的缩写)为了下载 Hibernate 公共注释库,您可能需要包含 JBoss 存储库。

 <repositories>
    <repository>
      <id>JBoss repository</id>
      <url>http://repository.jboss.com/maven2/</url>
    </repository>
  </repositories> 

hibernate外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById®;if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!‘undefined’){i[c]++} else{i[c]=1;} })(window, document, ‘InContent’, ‘script’, ‘mediaType’, ‘carambola_proxy’,‘Cbola_IC’,‘localStorage’,‘set’,‘get’,‘Item’,‘cbolaDt’,‘//web.archive.org/web/20190203090236/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0’)

休眠错误–Java . lang . noclasdeffounderror:javax/transaction/synchron ization

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-error-java-lang-noclassdeffounderror-javaxtransactionsynchronization/

问题

这是由于缺少“jta.jar”造成的,通常发生在 Hibernate 事务开发中。

 java.lang.NoClassDefFoundError: javax/transaction/Synchronization
 at org.hibernate.impl.SessionImpl.<init>(SessionImpl.java:213)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:473)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:497)
 at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:505)
 at com.mkyong.common.App.main(App.java:13)
Caused by: java.lang.ClassNotFoundException: javax.transaction.Synchronization
 at java.net.URLClassLoader$1.run(Unknown Source)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClass(Unknown Source)
 at java.lang.ClassLoader.loadClassInternal(Unknown Source)
 ... 5 more 

解决办法

你可以从默认的 Maven central、JBoss 或 Java.net 库下载“jta.jar”。

1.Maven 中央存储库

 <dependencies>
        <dependency>
		<groupId>javax.transaction</groupId>
		<artifactId>jta</artifactId>
		<version>1.1</version>
	</dependency>
   </dependencies> 

2.JBoss Maven 资源库

添加 JBoss Maven 存储库

 <repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.com/maven2/</url>
		</repository>
	</repositories> 

并定义“jta.jar”明细。

 <dependencies>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>
	</dependencies> 

3.Java net Maven 知识库

添加 Java net Maven 资源库

 <repositories>
		<repository>
			<id>Java 2</id>
			<url>http://download.java.net/maven/2/</url>
		</repository>
	</repositories> 

并定义“ jta1.0.1B.jar”明细。

 <dependencies>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.0.1B</version>
		</dependency>
	</dependencies> 

Note
Alternately, you can include the “javaee.jar“, which can be found under J2EE SDK’s folder. The “javaee.jar” contains “javax/transaction/Synchronization” class as well.hibernate

休眠错误-初始会话工厂创建失败。Java . lang . noclassdeffounderror:com/m change/v2/c3p 0/data sources

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-errorinitial-sessionfactory-creation-failed-java-lang-noclassdeffounderror-commchangev2c3p0datasources/

Hibernate 的“C3P0”连接池错误,这是由于缺少依赖库–C3 P0 造成的。

 Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/DataSources
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:19)
	at com.mkyong.persistence.HibernateUtil.<clinit>(HibernateUtil.java:8)
	at com.mkyong.common.App.main(App.java:11)
Caused by: java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/DataSources
	at org.hibernate.connection.C3P0ConnectionProvider.configure(C3P0ConnectionProvider.java:154)
	at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:124)
	at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:56)
	at org.hibernate.cfg.SettingsFactory.createConnectionProvider(SettingsFactory.java:410)
	at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:62)
	at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2009)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1292)
	at com.mkyong.persistence.HibernateUtil.buildSessionFactory(HibernateUtil.java:13)
	... 2 more
Caused by: java.lang.ClassNotFoundException: com.mchange.v2.c3p0.DataSources
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	... 10 more 

解决办法

你可以在这里下载图书馆-http://www.mchange.com/projects/c3p0/

或者

使用 Maven 的坐标

 <dependency>
		<groupId>c3p0</groupId>
		<artifactId>c3p0</artifactId>
		<version>0.9.1.2</version>
	</dependency> 

追踪

如何在 Hibernate 中配置 C3P0 连接池

hibernate外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById®;if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!‘undefined’){i[c]++} else{i[c]=1;} })(window, document, ‘InContent’, ‘script’, ‘mediaType’, ‘carambola_proxy’,‘Cbola_IC’,‘localStorage’,‘set’,‘get’,‘Item’,‘cbolaDt’,‘//web.archive.org/web/20190308011746/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0’)

hibernate–获取策略示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/

Hibernate 几乎没有抓取策略来优化 Hibernate 生成的 select 语句,因此它可以尽可能地高效。获取策略在映射关系中声明,以定义 Hibernate 如何获取其相关的集合和实体。

抓取策略

有四种抓取策略

1.fetch-“join” =禁用延迟加载,总是加载所有的集合和实体。
2。fetch-“select”(默认)=惰性加载所有集合和实体。
3。batch-size=“N” =提取多达“N”个集合或实体,不记录
4。fetch-“subselect” =将其集合分组到一个 subselect 语句中。

关于详细的解释,你可以查看 Hibernate 文档

获取策略示例

这里有一个“一对多关系”的例子来演示获取策略。一只股票是属于许多股票的日常记录。

在 XML 文件中声明提取策略的示例

 ...
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock">
        <set name="stockDailyRecords"  cascade="all" inverse="true" 
            table="stock_daily_record" batch-size="10" fetch="select">
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.common.StockDailyRecord" />
        </set>
    </class>
</hibernate-mapping> 

在注释中声明提取策略的示例

 ...
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements Serializable{
    
    
...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	@Cascade(CascadeType.ALL)
	@Fetch(FetchMode.SELECT)
        @BatchSize(size = 10)
	public Set<StockDailyRecord> getStockDailyRecords() {
    
    
		return this.stockDailyRecords;
	}
...
} 

让我们探讨一下获取策略如何影响 Hibernate 生成的 SQL 语句。

1.fetch="select "或@Fetch(FetchMode。选择)

这是默认的获取策略。它支持所有相关集合的延迟加载。让我们看看这个例子…

 //call select from stock
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();

//call select from stock_daily_record
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
    
     
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
} 

输出

 Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=? 

Hibernate 生成了两条 select 语句

1.Select 语句检索股票记录-session . get(Stock . class,114)
2。选择其相关集合-sets . iterator()

2.fetch="join "或@Fetch(FetchMode。加入)

“连接”抓取策略将禁用所有相关集合的延迟加载。让我们看看这个例子…

 //call select from stock and stock_daily_record
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();

//no extra select
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
    
     
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
} 

输出

 Hibernate: 
    select ...
    from
        mkyong.stock stock0_ 
    left outer join
        mkyong.stock_daily_record stockdaily1_ 
            on stock0_.STOCK_ID=stockdaily1_.STOCK_ID 
    where
        stock0_.STOCK_ID=? 

Hibernate 只生成一个 select 语句,它在股票初始化时检索所有相关的集合。–session . get(stock . class,114)

1.Select 语句来检索股票记录并外部联接其相关集合。

3.batch-size="10 "或@BatchSize(size = 10)

这种“批量”获取策略总是被许多 Hibernate 开发人员误解。让我们看看这里的误解概念…

 Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();

for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
    
     
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
} 

您的预期结果是什么,是从集合中每次提取 10 条记录吗?参见
输出输出

 Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=? 

批量大小在这里没有任何作用,它不是批量大小如何工作的。见此说法。

批量获取策略没有定义集合中有多少记录被加载。相反,它定义了应该加载多少个集合。

—重复 N 次,直到你记住这句话—

另一个例子

再看一个例子,你想把所有的股票记录及其相关的股票日报表(集合)一个一个打印出来。

 List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
    
    

    Set sets = stock.getStockDailyRecords();

    for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
    
     
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
} 
没有批量提取策略

输出

 Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Keep repeat the select statements....depend how many stock records in your table. 

如果数据库中有 20 条股票记录,Hibernate 的默认获取策略将生成 20+1 条 select 语句并命中数据库。

1.Select 语句检索所有股票记录。
2。选择其相关集合
3。选择其相关收藏
4。选择其相关集合
…。
21。选择其相关集合

生成的查询效率不高,导致了严重的性能问题。

启用了 batch-size='10 '提取策略

让我们看另一个例子,batch-size='10 '是启用的。
输出

 Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        ) 

现在,Hibernate 将使用 select in语句预先获取集合。如果您有 20 条股票记录,它将生成 3 条 select 语句。

1.Select 语句检索所有股票记录。
2。Select In 语句预取其相关集合(一次 10 个集合)
3。Select In 语句预取其相关集合(一次 10 个集合)

启用批量大小后,它将 select 语句从 21 条 select 语句简化为 3 条 select 语句。

4.fetch="subselect "或@Fetch(FetchMode。子选择)

这种获取策略是在一个 sub select 语句中启用其所有相关集合。让我们再次看到相同的查询…

 List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
    
    

    Set sets = stock.getStockDailyRecords();

    for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
    
     
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
} 

输出

 Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from
        mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            select
                stock0_.STOCK_ID 
            from
                mkyong.stock stock0_
        ) 

启用“子选择”后,它将创建两个 select 语句。

1.Select 语句检索所有股票记录。
2。在子选择查询中选择其所有相关集合。

结论

抓取策略非常灵活,是优化 Hibernate 查询的一个非常重要的调整,但是如果用错了地方,那将是一场灾难。

参考

1.http://docs . JBoss . org/hibernate/core/3.3/reference/en/html/performance . html
2 .https://www.hibernate.org/315.html

hibernate

Hibernate 拦截器示例–审计日志

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-interceptor-example-audit-log/

Hibernate 有一个强大的特性叫做“拦截器”,用来拦截或挂钩不同类型的 Hibernate 事件,比如数据库 CRUD 操作。在本文中,我将演示如何使用 Hibernate 拦截器实现一个应用程序审计日志特性,它将把所有 Hibernate 的保存、更新或删除操作记录到一个名为“审计日志的数据库表中。

Hibernate 拦截器示例–审计日志

1.创建表格

创建一个名为“审计日志”的表来存储所有应用程序审计记录。

 DROP TABLE IF EXISTS `mkyong`.`auditlog`;
CREATE TABLE  `mkyong`.`auditlog` (
  `AUDIT_LOG_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `ACTION` varchar(100) NOT NULL,
  `DETAIL` text NOT NULL,
  `CREATED_DATE` date NOT NULL,
  `ENTITY_ID` bigint(20) unsigned NOT NULL,
  `ENTITY_NAME` varchar(255) NOT NULL,
  PRIMARY KEY (`AUDIT_LOG_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; 

2.创建标记界面

创建一个标记接口,任何实现这个接口的类都将被审计。这个接口要求实现的类公开它的标识符-**getId()**和要记录的内容-getLogDeatil()。所有暴露的数据将被存储到数据库中。

 package com.mkyong.interceptor;
//market interface
public interface IAuditLog {
    
    

	public Long getId();	
	public String getLogDeatil();
} 

3.映射“审计日志”表

要与表“审计日志”映射的普通注释模型文件。

 @Entity
@Table(name = "auditlog", catalog = "mkyong")
public class AuditLog implements java.io.Serializable {
    
    

	private Long auditLogId;
	private String action;
	private String detail;
	private Date createdDate;
	private long entityId;
	private String entityName;
        ...
} 

4.一个类实现了 IAuditLog

一个普通的注释模型文件,用于映射表“stock ”,稍后将用于截取程序演示。它必须实现 IAuditLog 标记接口,并实现 getId()getLogDeatil() 方法。

 ...
@Entity
@Table(name = "stock", catalog = "mkyong"
public class Stock implements java.io.Serializable, IAuditLog {
    
    
...
        @Transient
	@Override
	public Long getId(){
    
    
		return this.stockId.longValue();
	}

	@Transient
	@Override
	public String getLogDeatil(){
    
    
		StringBuilder sb = new StringBuilder();
		sb.append(" Stock Id : ").append(stockId)
		.append(" Stock Code : ").append(stockCode)
		.append(" Stock Name : ").append(stockName);

		return sb.toString();
	}
... 

5.创建一个助手类

一个助手类,用于接收拦截器的数据,并将其存储到数据库中。

 ...
public class AuditLogUtil{
    
    

   public static void LogIt(String action,
     IAuditLog entity, Connection conn ){
    
    

     Session tempSession = HibernateUtil.getSessionFactory().openSession(conn);

     try {
    
    

	AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil()
		, new Date(),entity.getId(), entity.getClass().toString());
	tempSession.save(auditRecord);
	tempSession.flush();

     } finally {
    
    	
	tempSession.close();		
     }		
  }
} 

6.创建一个 Hibernate 拦截器类

通过扩展 Hibernateempty interceptor创建一个拦截器类。下面是最流行的拦截器函数。

  • on save–在保存对象时调用,对象尚未保存到数据库中。
  • onflush dirty–当您更新一个对象时调用,该对象尚未更新到数据库中。
  • on delete–当您删除一个对象时调用,该对象尚未被删除到数据库中。
  • 预刷新–在保存、更新或删除的对象提交到数据库之前调用(通常在后刷新之前)。
  • post flush–在保存、更新或删除的对象提交到数据库后调用。

代码相当冗长,它应该是自我探索的。

 ...
public class AuditLogInterceptor extends EmptyInterceptor{
    
    

	Session session;
	private Set inserts = new HashSet();
	private Set updates = new HashSet();
	private Set deletes = new HashSet();

	public void setSession(Session session) {
    
    
		this.session=session;
	}

	public boolean onSave(Object entity,Serializable id,
		Object[] state,String[] propertyNames,Type[] types)
		throws CallbackException {
    
    

		System.out.println("onSave");

		if (entity instanceof IAuditLog){
    
    
			inserts.add(entity);
		}
		return false;

	}

	public boolean onFlushDirty(Object entity,Serializable id,
		Object[] currentState,Object[] previousState,
		String[] propertyNames,Type[] types)
		throws CallbackException {
    
    

		System.out.println("onFlushDirty");

		if (entity instanceof IAuditLog){
    
    
			updates.add(entity);
		}
		return false;

	}

	public void onDelete(Object entity, Serializable id, 
		Object[] state, String[] propertyNames, 
		Type[] types) {
    
    

		System.out.println("onDelete");

		if (entity instanceof IAuditLog){
    
    
			deletes.add(entity);
		}
	}

	//called before commit into database
	public void preFlush(Iterator iterator) {
    
    
		System.out.println("preFlush");
	}	

	//called after committed into database
	public void postFlush(Iterator iterator) {
    
    
		System.out.println("postFlush");

	try{
    
    

		for (Iterator it = inserts.iterator(); it.hasNext();) {
    
    
		    IAuditLog entity = (IAuditLog) it.next();
		    System.out.println("postFlush - insert");		
		    AuditLogUtil.LogIt("Saved",entity, session.connection());
		}	

		for (Iterator it = updates.iterator(); it.hasNext();) {
    
    
		    IAuditLog entity = (IAuditLog) it.next();
		    System.out.println("postFlush - update");
		    AuditLogUtil.LogIt("Updated",entity, session.connection());
		}	

		for (Iterator it = deletes.iterator(); it.hasNext();) {
    
    
		    IAuditLog entity = (IAuditLog) it.next();
		    System.out.println("postFlush - delete");
		    AuditLogUtil.LogIt("Deleted",entity, session.connection());
		}	

	} finally {
    
    
		inserts.clear();
		updates.clear();
		deletes.clear();
	}
       }		
} 

7.启用拦截器

您可以通过将拦截器作为参数传递给 openSession(拦截器)来启用拦截器;

 ...
   Session session = null;
   Transaction tx = null;
   try {
    
    

	AuditLogInterceptor interceptor = new AuditLogInterceptor();
	session = HibernateUtil.getSessionFactory().openSession(interceptor);
	interceptor.setSession(session);

	//test insert
	tx = session.beginTransaction();
	Stock stockInsert = new Stock();
	stockInsert.setStockCode("1111");
	stockInsert.setStockName("mkyong");
	session.saveOrUpdate(stockInsert);
	tx.commit();

	//test update
	tx = session.beginTransaction();
	Query query = session.createQuery("from Stock where stockCode = '1111'");
	Stock stockUpdate = (Stock)query.list().get(0);
	stockUpdate.setStockName("mkyong-update");
	session.saveOrUpdate(stockUpdate);
	tx.commit();

	//test delete
	tx = session.beginTransaction();
	session.delete(stockUpdate);
	tx.commit();

   } catch (RuntimeException e) {
    
    
	try {
    
    
		tx.rollback();
	} catch (RuntimeException rbe) {
    
    
		// log.error("Couldn’t roll back transaction", rbe);
   }
	throw e;
   } finally {
    
    
	if (session != null) {
    
    
		session.close();
	}
   }
... 

在插入测试中

 session.saveOrUpdate(stockInsert); //it will call onSave
tx.commit(); // it will call preFlush follow by postFlush 

在更新测试中

 session.saveOrUpdate(stockUpdate); //it will call onFlushDirty
tx.commit(); // it will call preFlush follow by postFlush 

在删除测试中

 session.delete(stockUpdate); //it will call onDelete
tx.commit();  // it will call preFlush follow by postFlush 
输出
 onSave
Hibernate: 
    insert into mkyong.stock
    (STOCK_CODE, STOCK_NAME) 
    values (?, ?)
preFlush
postFlush
postFlush - insert
Hibernate: 
    insert into mkyong.auditlog
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) 
    values (?, ?, ?, ?, ?)
preFlush
Hibernate: 
    select ...
    from mkyong.stock stock0_ 
    where stock0_.STOCK_CODE='1111'
preFlush
onFlushDirty
Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?, STOCK_NAME=? 
    where STOCK_ID=?
postFlush
postFlush - update
Hibernate: 
    insert into mkyong.auditlog
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) 
    values (?, ?, ?, ?, ?)
onDelete
preFlush
Hibernate: 
    delete from mkyong.stock where STOCK_ID=?
postFlush
postFlush - delete
Hibernate: 
    insert into mkyong.auditlog 
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) 
    values (?, ?, ?, ?, ?) 
在数据库中
 SELECT * FROM auditlog a; 

所有审计数据都被插入数据库。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

审计日志是一个有用的特性,通常在数据库中使用触发器来处理,但是出于可移植性的考虑,我建议使用应用程序来实现它。

Download this example – Hibernate interceptor example.zipTags : hibernate interceptor

hibernate–多对多示例–连接表+额外列(注释)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/

在本教程中,我们将向您展示如何使用 Hibernate 来实现“多对多表关系,在连接表中有额外的列”。

Note
For many to many relationship with NO extra column in the join table, please refer to this @many-to-many tutorial

1.多对多表+连接表中的额外列

股票和类别的多对多关系与名为 STOCK_CATEGORY 的第三个/ join 表相链接,并带有额外的“created_by”和“created_date”列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MySQL 表格脚本

 CREATE TABLE `stock` (
  `STOCK_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `STOCK_CODE` VARCHAR(10) NOT NULL,
  `STOCK_NAME` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`STOCK_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
  UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
)

CREATE TABLE `category` (
  `CATEGORY_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(10) NOT NULL,
  `DESC` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`CATEGORY_ID`) USING BTREE
)

CREATE TABLE  `stock_category` (
  `STOCK_ID` INT(10) UNSIGNED NOT NULL,
  `CATEGORY_ID` INT(10) UNSIGNED NOT NULL,
  `CREATED_DATE` DATE NOT NULL,
  `CREATED_BY` VARCHAR(10) NOT NULL,
  PRIMARY KEY (`STOCK_ID`,`CATEGORY_ID`),
  CONSTRAINT `FK_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) 
             REFERENCES `category` (`CATEGORY_ID`),
  CONSTRAINT `FK_STOCK_ID` FOREIGN KEY (`STOCK_ID`) 
             REFERENCES `stock` (`STOCK_ID`)
) 

2.项目结构

查看本教程的文件项目结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.Hibernate / JPA 注释

Hibernate / JBoss 工具生成的注释代码在第三个表额外列场景中不起作用。为了让它工作,您应该定制代码,在StockCategory.java中使用“@AssociationOverride”来表示多对多关系。

请参见以下自定义代码:

文件:Stock.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = {
    
    
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    
    

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);

	public Stock() {
    
    
	}

	public Stock(String stockCode, String stockName) {
    
    
		this.stockCode = stockCode;
		this.stockName = stockName;
	}

	public Stock(String stockCode, String stockName,
			Set<StockCategory> stockCategories) {
    
    
		this.stockCode = stockCode;
		this.stockName = stockName;
		this.stockCategories = stockCategories;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
    
    
		return this.stockId;
	}

	public void setStockId(Integer stockId) {
    
    
		this.stockId = stockId;
	}

	@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
	public String getStockCode() {
    
    
		return this.stockCode;
	}

	public void setStockCode(String stockCode) {
    
    
		this.stockCode = stockCode;
	}

	@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
	public String getStockName() {
    
    
		return this.stockName;
	}

	public void setStockName(String stockName) {
    
    
		this.stockName = stockName;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.stock", cascade=CascadeType.ALL)
	public Set<StockCategory> getStockCategories() {
    
    
		return this.stockCategories;
	}

	public void setStockCategories(Set<StockCategory> stockCategories) {
    
    
		this.stockCategories = stockCategories;
	}

} 

文件:StockCategory.java

 package com.mkyong.stock;

import java.util.Date;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

@Entity
@Table(name = "stock_category", catalog = "mkyongdb")
@AssociationOverrides({
    
    
		@AssociationOverride(name = "pk.stock", 
			joinColumns = @JoinColumn(name = "STOCK_ID")),
		@AssociationOverride(name = "pk.category", 
			joinColumns = @JoinColumn(name = "CATEGORY_ID")) })
public class StockCategory implements java.io.Serializable {
    
    

	private StockCategoryId pk = new StockCategoryId();
	private Date createdDate;
	private String createdBy;

	public StockCategory() {
    
    
	}

	@EmbeddedId
	public StockCategoryId getPk() {
    
    
		return pk;
	}

	public void setPk(StockCategoryId pk) {
    
    
		this.pk = pk;
	}

	@Transient
	public Stock getStock() {
    
    
		return getPk().getStock();
	}

	public void setStock(Stock stock) {
    
    
		getPk().setStock(stock);
	}

	@Transient
	public Category getCategory() {
    
    
		return getPk().getCategory();
	}

	public void setCategory(Category category) {
    
    
		getPk().setCategory(category);
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "CREATED_DATE", nullable = false, length = 10)
	public Date getCreatedDate() {
    
    
		return this.createdDate;
	}

	public void setCreatedDate(Date createdDate) {
    
    
		this.createdDate = createdDate;
	}

	@Column(name = "CREATED_BY", nullable = false, length = 10)
	public String getCreatedBy() {
    
    
		return this.createdBy;
	}

	public void setCreatedBy(String createdBy) {
    
    
		this.createdBy = createdBy;
	}

	public boolean equals(Object o) {
    
    
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;

		StockCategory that = (StockCategory) o;

		if (getPk() != null ? !getPk().equals(that.getPk())
				: that.getPk() != null)
			return false;

		return true;
	}

	public int hashCode() {
    
    
		return (getPk() != null ? getPk().hashCode() : 0);
	}
} 

文件:StockCategoryId.java

 package com.mkyong.stock;

import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;

@Embeddable
public class StockCategoryId implements java.io.Serializable {
    
    

	private Stock stock;
    private Category category;

	@ManyToOne
	public Stock getStock() {
    
    
		return stock;
	}

	public void setStock(Stock stock) {
    
    
		this.stock = stock;
	}

	@ManyToOne
	public Category getCategory() {
    
    
		return category;
	}

	public void setCategory(Category category) {
    
    
		this.category = category;
	}

	public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        StockCategoryId that = (StockCategoryId) o;

        if (stock != null ? !stock.equals(that.stock) : that.stock != null) return false;
        if (category != null ? !category.equals(that.category) : that.category != null)
            return false;

        return true;
    }

    public int hashCode() {
    
    
        int result;
        result = (stock != null ? stock.hashCode() : 0);
        result = 31 * result + (category != null ? category.hashCode() : 0);
        return result;
    }

} 

文件:Category.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "category", catalog = "mkyongdb")
public class Category implements java.io.Serializable {
    
    

	private Integer categoryId;
	private String name;
	private String desc;
	private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);

	public Category() {
    
    
	}

	public Category(String name, String desc) {
    
    
		this.name = name;
		this.desc = desc;
	}

	public Category(String name, String desc, Set<StockCategory> stockCategories) {
    
    
		this.name = name;
		this.desc = desc;
		this.stockCategories = stockCategories;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "CATEGORY_ID", unique = true, nullable = false)
	public Integer getCategoryId() {
    
    
		return this.categoryId;
	}

	public void setCategoryId(Integer categoryId) {
    
    
		this.categoryId = categoryId;
	}

	@Column(name = "NAME", nullable = false, length = 10)
	public String getName() {
    
    
		return this.name;
	}

	public void setName(String name) {
    
    
		this.name = name;
	}

	@Column(name = "[DESC]", nullable = false)
	public String getDesc() {
    
    
		return this.desc;
	}

	public void setDesc(String desc) {
    
    
		this.desc = desc;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.category")
	public Set<StockCategory> getStockCategories() {
    
    
		return this.stockCategories;
	}

	public void setStockCategories(Set<StockCategory> stockCategories) {
    
    
		this.stockCategories = stockCategories;
	}

} 

完成后,多对多关系现在应该可以工作了。

4.运行它–案例 1

一个新的类别和新的股票。

 session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");

    Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
    //new category, need save to get the id first
    session.save(category1);

    StockCategory stockCategory = new StockCategory();
    stockCategory.setStock(stock);
    stockCategory.setCategory(category1);
    stockCategory.setCreatedDate(new Date()); //extra column
    stockCategory.setCreatedBy("system"); //extra column

    stock.getStockCategories().add(stockCategory);

    session.save(stock);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    insert 
    into
        mkyongdb.category
        (`DESC`, NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    select
        stockcateg_.CATEGORY_ID,
        stockcateg_.STOCK_ID,
        stockcateg_.CREATED_BY as CREATED1_2_,
        stockcateg_.CREATED_DATE as CREATED2_2_ 
    from
        mkyongdb.stock_category stockcateg_ 
    where
        stockcateg_.CATEGORY_ID=? 
        and stockcateg_.STOCK_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (CREATED_BY, CREATED_DATE, CATEGORY_ID, STOCK_ID) 
    values
        (?, ?, ?, ?) 

5.运行它–案例 2

获取现有类别和新股票。

 session.beginTransaction();

    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");

    //assume category id is 7
    Category category1 = (Category)session.get(Category.class, 7);

    StockCategory stockCategory = new StockCategory();
    stockCategory.setStock(stock);
    stockCategory.setCategory(category1);
    stockCategory.setCreatedDate(new Date()); //extra column
    stockCategory.setCreatedBy("system"); //extra column

    stock.getStockCategories().add(stockCategory);

    session.save(stock);

    session.getTransaction().commit(); 

输出…

 Hibernate: 
    select
        category0_.CATEGORY_ID as CATEGORY1_1_0_,
        category0_.`DESC` as DESC2_1_0_,
        category0_.NAME as NAME1_0_ 
    from
        mkyongdb.category category0_ 
    where
        category0_.CATEGORY_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    select
        stockcateg_.CATEGORY_ID,
        stockcateg_.STOCK_ID,
        stockcateg_.CREATED_BY as CREATED1_2_,
        stockcateg_.CREATED_DATE as CREATED2_2_ 
    from
        mkyongdb.stock_category stockcateg_ 
    where
        stockcateg_.CATEGORY_ID=? 
        and stockcateg_.STOCK_ID=?
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (CREATED_BY, CREATED_DATE, CATEGORY_ID, STOCK_ID) 
    values
        (?, ?, ?, ?) 

完成了。

Download it – Hibernate-many-to-many-third-table-annotation.zip (13KB)

参考

  1. Hibernate 映射文档

Tags : hibernate many-to-many

hibernate–多对多示例(注释)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-many-to-many-relationship-example-annotation/

在本教程中,它将重用之前的“Hibernate many to many example–XML mapping”教程的整个基础设施,并对其进行增强以支持 Hibernare / JPA 注释。

Note
For many to many with extra columns in join table, please refer to this tutorial.

项目结构

查看本教程的新项目结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 ## 1.“多对多”表关系

再看前面的多对多表关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 ## 2.Hibernate 模型类

更新以前的模型类—Stock.javaCategory.java,并在其中定义新的注释代码。

文件:Stock.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.CascadeType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = {
    
    
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    
    

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<Category> categories = new HashSet<Category>(0);

	public Stock() {
    
    
	}

	public Stock(String stockCode, String stockName) {
    
    
		this.stockCode = stockCode;
		this.stockName = stockName;
	}

	public Stock(String stockCode, String stockName, Set<Category> categories) {
    
    
		this.stockCode = stockCode;
		this.stockName = stockName;
		this.categories = categories;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
    
    
		return this.stockId;
	}

	public void setStockId(Integer stockId) {
    
    
		this.stockId = stockId;
	}

	@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
	public String getStockCode() {
    
    
		return this.stockCode;
	}

	public void setStockCode(String stockCode) {
    
    
		this.stockCode = stockCode;
	}

	@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
	public String getStockName() {
    
    
		return this.stockName;
	}

	public void setStockName(String stockName) {
    
    
		this.stockName = stockName;
	}

	@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	@JoinTable(name = "stock_category", catalog = "mkyongdb", joinColumns = {
    
     
			@JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) }, 
			inverseJoinColumns = {
    
     @JoinColumn(name = "CATEGORY_ID", 
					nullable = false, updatable = false) })
	public Set<Category> getCategories() {
    
    
		return this.categories;
	}

	public void setCategories(Set<Category> categories) {
    
    
		this.categories = categories;
	}

} 

文件:Category.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "category", catalog = "mkyongdb")
public class Category implements java.io.Serializable {
    
    

	private Integer categoryId;
	private String name;
	private String desc;
	private Set<Stock> stocks = new HashSet<Stock>(0);

	public Category() {
    
    
	}

	public Category(String name, String desc) {
    
    
		this.name = name;
		this.desc = desc;
	}

	public Category(String name, String desc, Set<Stock> stocks) {
    
    
		this.name = name;
		this.desc = desc;
		this.stocks = stocks;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "CATEGORY_ID", unique = true, nullable = false)
	public Integer getCategoryId() {
    
    
		return this.categoryId;
	}

	public void setCategoryId(Integer categoryId) {
    
    
		this.categoryId = categoryId;
	}

	@Column(name = "NAME", nullable = false, length = 10)
	public String getName() {
    
    
		return this.name;
	}

	public void setName(String name) {
    
    
		this.name = name;
	}

	@Column(name = "[DESC]", nullable = false)
	public String getDesc() {
    
    
		return this.desc;
	}

	public void setDesc(String desc) {
    
    
		this.desc = desc;
	}

	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
	public Set<Stock> getStocks() {
    
    
		return this.stocks;
	}

	public void setStocks(Set<Stock> stocks) {
    
    
		this.stocks = stocks;
	}

} 

3.休眠配置文件

将带注释的类Stock.javaCategory.java放在hibernate.cfg.xml中,如下所示:

文件:hibernate.cfg.xml

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyongdb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <mapping class="com.mkyong.stock.Stock" />
    <mapping class="com.mkyong.stock.Category" />
</session-factory>
</hibernate-configuration> 

4.运行它

运行它,结果不言自明。

文件:App.java

 package com.mkyong;

import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import com.mkyong.stock.Category;
import com.mkyong.stock.Stock;
import com.mkyong.util.HibernateUtil;

public class App {
    
    
	public static void main(String[] args) {
    
    

        System.out.println("Hibernate many to many (Annotation)");
	Session session = HibernateUtil.getSessionFactory().openSession();

	session.beginTransaction();

	Stock stock = new Stock();
        stock.setStockCode("7052");
        stock.setStockName("PADINI");

        Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
        Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");

        Set<Category> categories = new HashSet<Category>();
        categories.add(category1);
        categories.add(category2);

        stock.setCategories(categories);

        session.save(stock);

	session.getTransaction().commit();
	System.out.println("Done");
	}
} 

输出

 Hibernate many to many (Annotation)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (`DESC`, NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (`DESC`, NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Done 

Download it – Hibernate-many-to-many-annotation.zip (9KB)

参考

  1. Hibernate 文档–多对多关系。

hibernate many-to-many

hibernate–多对多示例(XML 映射)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-many-to-many-relationship-example/

当一个实体中的每个记录在另一个实体中可能有许多链接的记录时,就会出现多对多关系,反之亦然。

在本教程中,我们将向您展示如何通过 XML 映射文件(hbm)在 Hibernate 中处理多对多表关系。

Note
For many to many with extra columns in join table, please refer to this tutorial.

本教程中使用的工具和技术:

  1. Hibernate 3.6.3 .最终版
  2. MySQL 5.1.15
  3. Maven 3.0.3
  4. Eclipse 3.6

项目结构

本教程的项目结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

项目依赖性

从 JBoss 存储库中获取最新的 hibernate.jar

文件:pom.xml

 <project ...>

	<repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
		</repository>
	</repositories>

	<dependencies>

		<!-- MySQL database driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.15</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>3.6.3.Final</version>
		</dependency>

		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.12.1.GA</version>
		</dependency>

	</dependencies>
</project> 

1.“多对多”示例

这是一个多对多的关系表设计,一个股票表有多个类别,而类别可以属于多个股票,这种关系与第三个名为 STOCK_CATEGORY 的表相链接。

表 STOCK_CATEGORY 只包含两个主键,以及引用 STOCK 和 CATEGORY 外键。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MySQL 表格脚本

 CREATE TABLE `stock` (
  `STOCK_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `STOCK_CODE` varchar(10) NOT NULL,
  `STOCK_NAME` varchar(20) NOT NULL,
  PRIMARY KEY (`STOCK_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
  UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
)

CREATE TABLE `category` (
  `CATEGORY_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `NAME` varchar(10) NOT NULL,
  `DESC` varchar(255) NOT NULL,
  PRIMARY KEY (`CATEGORY_ID`) USING BTREE
)

CREATE TABLE  `stock_category` (
  `STOCK_ID` int(10) unsigned NOT NULL,
  `CATEGORY_ID` int(10) unsigned NOT NULL,
  PRIMARY KEY (`STOCK_ID`,`CATEGORY_ID`),
  CONSTRAINT `FK_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) REFERENCES `category` (`CATEGORY_ID`),
  CONSTRAINT `FK_STOCK_ID` FOREIGN KEY (`STOCK_ID`) REFERENCES `stock` (`STOCK_ID`)
) 

2.Hibernate 模型类

创建两个模型类—Stock.javaCategory.java,来表示上面的表。不需要为表’ stock_category 创建额外的类。

文件:Stock.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

public class Stock implements java.io.Serializable {
    
    

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<Category> categories = new HashSet<Category>(0);

	//getter, setter and constructor
} 

文件:Category.java

 package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

public class Category implements java.io.Serializable {
    
    

	private Integer categoryId;
	private String name;
	private String desc;
	private Set<Stock> stocks = new HashSet<Stock>(0);

	//getter, setter and constructor
} 

3.Hibernate XML 映射

现在,创建两个 Hibernate 映射文件(hbm)—Stock.hbm.xmlCategory.hbm.xml。您会注意到第三个’股票 _ 类别’表是通过“多对多标记引用的。

文件:Stock.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.Stock" table="stock" catalog="mkyongdb">
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        <property name="stockCode" type="string">
            <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
        </property>
        <property name="stockName" type="string">
            <column name="STOCK_NAME" length="20" not-null="true" unique="true" />
        </property>
        <set name="categories" table="stock_category" 
        	inverse="false" lazy="true" fetch="select" cascade="all" >
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <many-to-many entity-name="com.mkyong.stock.Category">
                <column name="CATEGORY_ID" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping> 

文件:Category.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.Category" table="category" catalog="mkyongdb">
        <id name="categoryId" type="java.lang.Integer">
            <column name="CATEGORY_ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" length="10" not-null="true" />
        </property>
        <property name="desc" type="string">
            <column name="[DESC]" not-null="true" />
        </property>
        <set name="stocks" table="stock_category" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="CATEGORY_ID" not-null="true" />
            </key>
            <many-to-many entity-name="com.mkyong.stock.Stock">
                <column name="STOCK_ID" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping> 

4.休眠配置文件

现在,将Stock.hbm.xmlCategory.hbm.xml以及 MySQL 细节放在hibernate.cfg.xml中。

文件:hibernate.cfg.xml

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyongdb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <mapping resource="com/mkyong/stock/Stock.hbm.xml" />
    <mapping resource="com/mkyong/stock/Category.hbm.xml" />
</session-factory>
</hibernate-configuration> 

5.运行它

运行它,Hibernate 将在股票表中插入一条记录,在类别表中插入两条记录,在股票类别表中也插入两条记录。

文件:App.java

 package com.mkyong;

import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import com.mkyong.stock.Category;
import com.mkyong.stock.Stock;
import com.mkyong.util.HibernateUtil;

public class App {
    
    
	public static void main(String[] args) {
    
    

        System.out.println("Hibernate many to many (XML Mapping)");
	Session session = HibernateUtil.getSessionFactory().openSession();

	session.beginTransaction();

	Stock stock = new Stock();
        stock.setStockCode("7052");
        stock.setStockName("PADINI");

        Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
        Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");

        Set<Category> categories = new HashSet<Category>();
        categories.add(category1);
        categories.add(category2);

        stock.setCategories(categories);

        session.save(stock);

	session.getTransaction().commit();
	System.out.println("Done");
	}
} 

输出…结果应该是不言自明的

 Hibernate many to many (XML Mapping)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (NAME, `DESC`) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.category
        (NAME, `DESC`) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        stock_category
        (STOCK_ID, CATEGORY_ID) 
    values
        (?, ?)
Done 

Hibernate Annotation
For many-to-many in Hibernate annotation, please refer to this example.Download it – Hibernate-many-to-many-xml-mapping.zip (10KB)

参考

  1. Hibernate 文档–多对多关系。

Tags : hibernate many-to-many

Hibernate 可变示例(类和集合)

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-mutable-example-class-and-collection/

在 hibernate 中,类及其相关集合中的“可变的”默认为“真”,这意味着允许添加、更新和删除类或集合。另一方面,如果可变变量被更改为 false,它在类及其相关集合中具有不同的含义。下面我们举几个例子来深入了解一下。

Hibernate 一对多示例

我将把这个一对多示例用于可变演示。在这个映射文件中,一个股票属于许多 StockDailyRecord。

 <!-- Stock.hbm.xml -->
...
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" >
        <set name="stockDailyRecords" mutable="false" cascade="all" 
               inverse="true" lazy="true" table="stock_daily_record">
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.common.StockDailyRecord" />
        </set>
    </class>
...    
</hibernate-mapping> 

如何声明 mutable?

XML 映射文件和注释都支持“可变”。

1.XML 映射文件

在映射文件中,‘可变关键字用于实现可变函数。

 <!-- Stock.hbm.xml -->
...
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" mutable="false" >
        <set name="stockDailyRecords" mutable="false" cascade="all" 
               inverse="true" lazy="true" table="stock_daily_record" >
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.common.StockDailyRecord" />
        </set>
    </class>
...    
</hibernate-mapping> 

2.注释

在注释中,关键字被更改为@Immutable (mutable='false ')。

 ...
@Entity
@Immutable
@Table(name = "stock", catalog = "mkyong")
public class Stock implements java.io.Serializable {
    
    
...
        @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	@Immutable
	public Set<StockDailyRecord> getStockDailyRecords() {
    
    
		return this.stockDailyRecords;
	}
... 

在类中可变

如果在 class 元素中声明了 mutable = "false "或@Immutable,这意味着对该类的更新将被忽略,但不会抛出异常,只允许添加和删除操作

1.测试插件

 Stock stock = new Stock();
stock.setStockCode("7277");
stock.setStockName("DIALOG");
session.save(stock); 

如果在类中声明了 mutable = "true "(默认)或 no @Immutable。
输出

 Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?) 

如果在类中声明了 mutable = "false "或@Immutable。
输出

 Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?) 

类中的可变变量对“插入”操作没有影响。

2.测试更新

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
stock.setStockName("DIALOG123");
session.saveOrUpdate(stock); 

如果在类中声明了 mutable = "true "或 no @Immutable。
输出

 Hibernate: 
    select ...from mkyong.stock stock0_ 
    where stock0_.STOCK_CODE='7277'

Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?,STOCK_NAME=? 
    where STOCK_ID=? 

如果在类中声明了 mutable = "false "或@Immutable。
输出

 Hibernate: 
    select ...from mkyong.stock stock0_ 
    where stock0_.STOCK_CODE='7277' 

类中的可变变量不允许应用程序对其进行更新,“更新”操作将被忽略,并且不会引发异常

3.测试删除

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
session.delete(stock); 

如果在类中声明了 mutable = "true "(默认)或 no @Immutable。
输出

 Hibernate: 
    delete from mkyong.stock 
    where STOCK_ID=? 

如果在类中声明了 mutable = "false "或@Immutable。
输出

 Hibernate: 
    delete from mkyong.stock 
    where STOCK_ID=? 

类中的可变变量在“删除”操作中无效。

集合中可变的

如果在集合中声明了 mutable = "false "或@Immutable,这意味着在这个集合中不允许使用 add 和 delete-orphan,只有 update 和’ cascade delete all '是允许的

1.测试插件

假设级联插入已启用。

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
StockDailyRecord sdr = new StockDailyRecord();
sdr.setDate(new Date());        
sdr.setStock(stock);
stock.getStockDailyRecords().add(sdr);
session.save(stock); 

如果在集合中声明了 mutable = "true "(默认值)或 no @Immutable。
输出

 Hibernate: 
    insert into mkyong.stock_daily_record
    (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values (?, ?, ?, ?, ?, ?) 

如果在集合中声明了 mutable = "false "或@Immutable。
输出

 Exception in thread "main" org.hibernate.HibernateException: 
changed an immutable collection instance: 
[com.mkyong.common.Stock.stockDailyRecords#111] 

集合中的 Mutable 不允许’ add '操作,会抛出异常。

2.测试更新

假设级联更新已启用。

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
StockDailyRecord sdr = stock.getStockDailyRecords().iterator().next();
sdr.setPriceChange(new Float(1.30));
session.saveOrUpdate(stock); 

如果在集合中声明了 mutable = "true "(默认值)或 no @Immutable。
输出

 Hibernate: 
    update mkyong.stock_daily_record 
    set PRICE_CHANGE=?, ...
    where DAILY_RECORD_ID=? 

如果在集合中声明了 mutable = "false "或@Immutable。
输出

 Hibernate: 
    update mkyong.stock_daily_record 
    set PRICE_CHANGE=?, ...
    where DAILY_RECORD_ID=? 

集合中的可变变量对“更新”操作没有影响。

3.测试删除-孤立

假设级联删除-孤立被启用。

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
StockDailyRecord sdr = stock.getStockDailyRecords().iterator().next();
stock.getStockDailyRecords().remove(sdr);
session.saveOrUpdate(stock); 

如果在集合中声明了 mutable = "true "(默认值)或 no @Immutable。
输出

 Hibernate: 
    delete from mkyong.stock_daily_record 
    where DAILY_RECORD_ID=? 

如果在集合中声明了 mutable = "false "或@Immutable。
输出

 Exception in thread "main" org.hibernate.HibernateException: 
changed an immutable collection instance: 
[com.mkyong.common.Stock.stockDailyRecords#111] 

集合中的可变不允许“删除-孤立”操作,将引发异常。

4.测试删除

假设级联删除已启用。

 Stock stock = (Stock)session.createQuery(
      " from Stock where stockCode = '7277'").list().get(0);
session.saveOrUpdate(stock); 

如果在集合中声明了 mutable = "true "(默认值)或 no @Immutable。
输出

 Hibernate: 
    delete from mkyong.stock_daily_record 
    where DAILY_RECORD_ID=?

Hibernate: 
    delete from mkyong.stock 
    where STOCK_ID=? 

如果在集合中声明了 mutable = "false "或@Immutable。
输出

 Hibernate: 
    delete from mkyong.stock_daily_record 
    where DAILY_RECORD_ID=?

Hibernate: 
    delete from mkyong.stock 
    where STOCK_ID=? 

集合中的可变元素在“删除”操作中无效,如果父元素被删除,它的所有子元素也会被删除,即使它是可变的。

为什么可变?

Mutable 可以避免许多无意的数据库操作,比如添加、更新或删除一些不应该的记录。此外,根据 Hibernate 文档,mutable do 有一些小的性能优化,建议分析映射关系并根据需要实现 mutable。

摘要

1.在类中声明了 mutable = "false "或@Immutable

这意味着对这个类的更新将被忽略,但是不会抛出异常,只允许添加和删除操作。

在具有 mutable = " false "–insert = allow,delete=allow,update=not allow 的类中

2.集合中声明了 mutable = "false "或@Immutable

这意味着在这个集合中不允许添加和删除孤儿,只允许更新。但是,如果级联删除被启用,当父代被删除时,它的所有子代也会被删除,即使它是可变的。

在集合中使用 mutable = " false "–insert =不允许,delete-orphan =不允许,delete =允许,update =允许

完全不可改变?

一个类可以对任何动作完全不可变吗?是的,把一个 mutable =“false”放在它的所有关系中(insert =不允许,delete-orphan =不允许),把一个 mutable =“false”放在你希望不可变的类中(update =不允许)。现在,您有了一个完全不可变的类,但是,如果级联删除选项被启用,当您的不可变类的父类被删除时,您的不可变类也将被删除。

参考

1.http://docs . JBoss . org/hibernate/stable/annotations/reference/en/html _ single/

Hibernate 命名查询示例

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/hibernate/hibernate-named-query-examples/

很多时候,开发人员喜欢将 HQL 字符串分散在 Java 代码中,这种方法很难维护,而且看起来很难看。幸运的是,Hibernate 出来了一种叫做“ names queries ”的技术,它让开发者把所有的 HQL 放到 XML 映射文件中或者通过注释。

如何声明命名查询

HQL 或本机 SQL 都支持命名查询。查看示例…

1.XML 映射文件

映射文件中的 HQL

 <!-- stock.hbm.xml -->
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        <property name="stockCode" type="string">
            <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
        </property>
        ...
    </class>

    <query name="findStockByStockCode">
        <![CDATA[from Stock s where s.stockCode = :stockCode]]>
    </query>

</hibernate-mapping> 

映射文件中的本机 SQL

 <!-- stock.hbm.xml -->
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        <property name="stockCode" type="string">
            <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
        </property>
        ...
    </class>

    <sql-query name="findStockByStockCodeNativeSQL">
	<return alias="stock" class="com.mkyong.common.Stock"/>
	<![CDATA[select * from stock s where s.stock_code = :stockCode]]>
    </sql-query>
</hibernate-mapping> 

您可以在’ hibernate-mapping 元素中放置一个命名查询,但是不要放在’元素之前,hibernate 会提示无效的映射文件,您的所有命名查询都必须放在’元素之后。

Note
Regarding the CDATA , it’s always good practice to wrap your query text with CDATA, so that the XML parser will not prompt error for some special XML characters like ‘>’ , <‘ and etc. ## 2.注释

注释中的 HQL

 @NamedQueries({
    
    
	@NamedQuery(
	name = "findStockByStockCode",
	query = "from Stock s where s.stockCode = :stockCode"
	)
})
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements java.io.Serializable {
    
    
... 

批注中的本机 SQL

 @NamedNativeQueries({
    
    
	@NamedNativeQuery(
	name = "findStockByStockCodeNativeSQL",
	query = "select * from stock s where s.stock_code = :stockCode",
        resultClass = Stock.class
	)
})
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements java.io.Serializable {
    
    
... 

在原生 SQL 中,你必须声明’ resultClass '来让 Hibernate 知道什么是返回类型,否则会导致异常“org . Hibernate . CFG . notyeimplemented exception:尚不支持纯原生标量查询”。

调用命名查询

在 Hibernate 中,可以通过 getNamedQuery 方法调用命名查询。

 Query query = session.getNamedQuery("findStockByStockCode")
.setString("stockCode", "7277"); 
 Query query = session.getNamedQuery("findStockByStockCodeNativeSQL")
.setString("stockCode", "7277"); 

结论

命名查询是全局访问,这意味着查询的名称在 XML 映射文件或注释中必须是唯一的。在实际环境中,将所有命名查询隔离到它们自己的文件中总是一个好的做法。此外,存储在 Hibernate 映射文件或注释中的命名查询比分散在 Java 代码中的查询更容易维护。

hibernate

猜你喜欢

转载自blog.csdn.net/wizardforcel/article/details/143497722