Hibernate Transaction handle example

In Hibernate, the transaction management is quite standard, just remember any exceptions thrown by Hibernate are FATAL, you have to roll back the transaction and close the current session immediately.

Here’s a Hibernate transaction template :

        Session session = null;
    	Transaction tx = null;
 
    	try{
    		session = HibernateUtil.getSessionFactory().openSession();
    		tx = session.beginTransaction();
    		tx.setTimeout(5);
 
    		//doSomething(session);
 
    		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();
    		}
    	}
How to know from where a Class was loaded in Java

Here’s a tip to demonstrate how to know from where a Java Class was loaded in Java.

Java Example

Here’s an example to load a Java class called “Address “, package in “com.mkyong.io“, and print out the location from where this class was loaded.

import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
 
public class App{
 
	public static void main(String[] args) {
 
	try{
 
		Class cls = Class.forName("com.mkyong.io.Address");		
		ProtectionDomain pd = cls.getProtectionDomain(); 
		CodeSource cs = pd.getCodeSource(); 
		URL url = cs.getLocation();
		System.out.println(url.getFile());
 
	}catch(Exception ex){
		ex.printStackTrace();
	}
 }
}

Output

/E:/workspace/HibernateExample/target/classes/

The Java class “Address” is located at “E:/workspace/HibernateExample/target/classes/com/mkyong/io/Address.class

Hibernate – Many-to-many relationship example

Many-to-many relationships occur when each record in an entity may have many linked records in another entity and vice-versa.

“Many-to-many” example

This is a many-to-many relationship table design, a STOCK table has more than one CATEGORY, and CATEGORY can belong to more than one STOCK, the relationship is linked with a third table called STOCK_CATEGORY.

many-to-many-relationship

Hibernate implementation

In Hibernate, this “many-to-many” relationship can implemented in two ways :

  • Hibernate XML Mapping file
  • Hibernate Annotation

1. Hibernate XML mapping file

In XML mapping way, you need three Java classes to hold the table data,

  • Stock.java -> STOCK table
  • Category.java -> CATEGORY table
  • StockCategory.java -> STOCK_CATEGORY table

and three XML mapping files to describe the table relationship.

  • Stock.hbm.xml -> STOCK table
  • Category.hbm.xml -> CATEGORY table
  • StockCategory.hbm.xml -> STOCK_CATEGORY table
Stock.java
public class Stock implements java.io.Serializable {
   private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);
   ...
   public Set<StockCategory> getStockCategories() {
	return this.stockCategories;
   }
 
   public void setStockCategories(Set<StockCategory> stockCategories) {
	this.stockCategories = stockCategories;
   }
Category.java
public class Category implements java.io.Serializable {
   private Set<StockCategory> stockCategories = new HashSet<StockCategory>(0);
   ...
   public Set<StockCategory> getStockCategories() {
	return this.stockCategories;
   }
 
   public void setStockCategories(Set<StockCategory> stockCategories) {
	this.stockCategories = stockCategories;
   }
StockCategory.java
public class StockCategory implements java.io.Serializable {
   private Integer stockCategoryId;
   private Stock stock;
   private Category category;
   ...
Stock.hbm.xml
...
<class name="com.mkyong.common.Stock" table="stock" ...>
   <id name="stockId" type="java.lang.Integer">
      <column name="STOCK_ID" />
      <generator class="identity" />
   </id>
   ...
   <set name="stockCategories" inverse="true" lazy="true" 
       table="stock_category" ...>
       <key>
         <column name="STOCK_ID" not-null="true" />
       </key>
          <one-to-many class="com.mkyong.common.StockCategory" />
   </set>
...

Set inverse=”true” in set variable, Stock does not want to maintain the relationship.

Category.hbm.xml
...
<class name="com.mkyong.common.Category" table="category" ...>
   <id name="categoryId" type="java.lang.Integer">
       <column name="CATEGORY_ID" />
       <generator class="identity" />
   </id>
   ...
   <set name="stockCategories" inverse="true" lazy="true" 
       table="stock_category" ...>
      <key>
         <column name="CATEGORY_ID" not-null="true" />
      </key>
         <one-to-many class="com.mkyong.common.StockCategory" />
   </set>
...

Set inverse=”true” in set variable, Category does not want to maintain the relationship also.

StockCategory.hbm.xml
...
<class name="com.mkyong.common.StockCategory" table="stock_category" ...>
   <id name="stockCategoryId" type="java.lang.Integer">
      <column name="STOCK_CATEGORY_ID" />
      <generator class="identity" />
   </id>
   <many-to-one name="stock" class="com.mkyong.common.Stock" ...>
       <column name="STOCK_ID" not-null="true" />
   </many-to-one>
   <many-to-one name="category" class="com.mkyong.common.Category" ...>
        <column name="CATEGORY_ID" not-null="true" />
    </many-to-one>
</class>
...

StockCategory maintain the relationship between Stock and Category, see inverse=”true” explanation.

2. Hibernate annotation

In annotation way, three classes are required, all the relationships are declared inside the Java classes.

  • Stock.java -> STOCK table
  • category.java -> CATEGORY table
  • StockCategory.java -> STOCK_CATEGORY table
Stock.java
...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
	private Set<StockCategory> stockCategories = 
                                         new HashSet<StockCategory>(0);
	...
	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
		return this.stockId;
	}
        ...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	public Set<StockCategory> getStockCategories() {
		return this.stockCategories;
	}
 
	public void setStockCategories(Set<StockCategory> stockCategories) {
		this.stockCategories = stockCategories;
	}
...
Category.java
...
@Entity
@Table(name = "category", catalog = "mkyong")
public class Category implements java.io.Serializable {
	private Set<StockCategory> stockCategories = 
                                       new HashSet<StockCategory>(0);
        ...
	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "CATEGORY_ID", unique = true, nullable = false)
	public Integer getCategoryId() {
		return this.categoryId;
	}
	...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
	public Set<StockCategory> getStockCategories() {
		return this.stockCategories;
	}
 
	public void setStockCategories(Set<StockCategory> stockCategories) {
		this.stockCategories = stockCategories;
	}
...
StockCategory.java
@Entity
@Table(name = "stock_category", catalog = "mkyong", 
        uniqueConstraints = @UniqueConstraint(columnNames = {
        "STOCK_ID", "CATEGORY_ID" }))
public class StockCategory implements java.io.Serializable {
	private Integer stockCategoryId;
	private Stock stock;
	private Category category;
	...
	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "STOCK_CATEGORY_ID", unique = true, nullable = false)
	public Integer getStockCategoryId() {
		return this.stockCategoryId;
	}
 
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "STOCK_ID", nullable = false)
	public Stock getStock() {
		return this.stock;
	}
 
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "CATEGORY_ID", nullable = false)
	public Category getCategory() {
		return this.category;
	}
...

The code is self-explanatory, all the @annotation are the XML mapping tag substitution.

Test It

Run the example, both annotation and XML mapping file will generate the same output. Hibernate inserts a row into the STOCK table, a row into the CATEGORY table, and both relationship in STOCK_CATEGORY table.

        Stock stock = new Stock(); 
        Category category = new Category();
        ...
        session.save(stock);
        session.save(category);
        ...
        StockCategory stockCategory = new StockCategory(stock, category);
        session.save(stockCategory);
Output
Hibernate: 
    insert into mkyong.stock
    (STOCK_CODE, STOCK_NAME) 
    values (?, ?)
 
Hibernate: 
    insert into mkyong.category
    (`DESC`, NAME) 
    values (?, ?)
 
Hibernate: 
    insert into mkyong.stock_category
    (CATEGORY_ID, STOCK_ID) 
    values (?, ?)

Download Full Project

In this tutorial, many files and configuration steps are hidden, only the important files are remark. If you are interest to do the hand-on, you can download the full project here.

These two projects are developed in Eclipse IDE, using Maven as project management tool, and MySQL as database engine. The MySQL table creation scripts are stored in “db” folder.

How to prevent others steal your web image (hotlinking)

My website’s images are keep directly link (hotlinking) by other websites, it’s a thief behavior and eating my bandwidth, why don’t they copy to their own server and display it? I decided to take action to stop this happened again, this so called “hotlinking” can be stopped by “.htaccess” access control.

Case Study

1. Hotlinking my image

This website is directly link to my website image

steal-nohotlink

2. Design custom image

Create a custom image with paint, save it as “nohotlink.jpe“. This image file will use as your linked image replacement. Just put some text like “do not steal my bandwidth”, and upload to your server image folder.

This is my custom image

nohotlink

3. “.htaccess”

Place a file called .htaccess in your hosting’s Apache root directory. e.g /public_html/.htcaccess

Put this text into your .htaccess file.

# BEGIN prevent hotlinking image
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?yourwebsitehere\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ /image/nohotlink.jpe [L]
</IfModule>
# END prevent hotlinking image

Replace the text “yourwebsitehere” with your website name. More explanation here

4. Test

The image is replace with your custom image ~

steal-nohotlink-1

Alternative solution

The alternative solution is watermark your image, but it is steal eat up your bandwidth.

Conclusion

I just do not like this kind of direct image link behavior, please do not steal like this, why not just print screen and put the image in your server? It’s quite easy also :) ~

Cascade – JPA & Hibernate annotation common mistake

Often times, developers are mix used the JPA and Hibernate annotation together, it will caused a very common mistake – JPA cascade type annotation is not working in Hibernate?

During the code review section, i find out many Java developers are not aware of this mistake and causing the program failed to execute the cascade operation to the related entities. I will take this one-to-many hibernate example for the demonstration.

Mistake

In the one-to-many example, many developers declared the JPA cascade options as following :

...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    ...
    private Set<StockDailyRecord> stockDailyRecords = 
                                              new HashSet<StockDailyRecord>(0);
 
    @OneToMany(fetch = FetchType.LAZY, 
       cascade = {CascadeType.PERSIST,CascadeType.MERGE }, 
       mappedBy = "stock")
    public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
    }
 
    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
    }
    ...

Save it with Hibernate session.

        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stock);
        session.getTransaction().commit();

What the code trying to do is when you save a “stock”, it will save the associated stockDailyRecords as well. Everything look fine, but THIS IS NOT WORKING, the cascade options will not execute and save the stockDailyRecords. Can you spot the mistake?

Explanation

Look in the code, @OneToMany is from JPA , it expected a JPA cascade – javax.persistence.CascadeType. However when you save it with Hibernate session, org.hibernate.engine.Cascade will do the following checking …

	if ( style.doCascade( action ) ) {
		cascadeProperty(
	          persister.getPropertyValue( parent, i, entityMode ),
		  types[i],
    	          style,
	          anything,
	          false
		);
	}

The Hibernate save process will causing a ACTION_SAVE_UPDATE action, but the JPA will pass a ACTION_PERSIST and ACTION_MERGE, it will not match and causing the cascade failed to execute.

@see source code

  • org.hibernate.engine.Cascade
  • org.hibernate.engine.CascadeStyle
  • org.hibernate.engine.CascadingAction

Solution

Delete the JPA cascade – javax.persistence.CascadeType, replace it with Hibernate cascade – org.hibernate.annotations.Cascade, with CascadeType.SAVE_UPDATE.

...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    ...
    private Set<StockDailyRecord> stockDailyRecords = 
                                              new HashSet<StockDailyRecord>(0);
 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    @Cascade({CascadeType.SAVE_UPDATE})
    public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
    }
 
    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
    }
    ...

Now, it work as what you expected.

Conclusion

It look like an incompatible issue between JPA and Hibernate cascade annotation, if Hibernate is a JPA implementation, what may causing the misunderstand in between?