Hibernate mutable example (class and collection)
In hibernate, ‘mutable‘ is default to ‘true’ in class and its related collection, it mean the class or collection are allow to add, update and delete. On the other hand, if the mutable is changed to false, it has different meaning in class and its related collection. Let’s take some examples to understand more about it.
Hibernate one-to-many example
I will take this one-to-many example for the mutable demonstration. In this mapping file, a Stock is belong to many 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>
How to declare mutable ?
The ‘mutable’ is support both in XML mapping file and annotation.
1. XML mapping file
In mapping file, the ‘mutable‘ keyword is use to implement the mutable function.
<!-- 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. Annotation
In annotation, the keyword is changed to @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;
}
...
Mutable in class
If mutable = “false” or @Immutable is declared in class element, it means the updates to this class will be ignored, but no exception is thrown, only the add and delete operation are allow.
1. Test insert
Stock stock = new Stock();
stock.setStockCode("7277");
stock.setStockName("DIALOG");
session.save(stock);
if mutable = “true” (default) or no @Immutable is declared in class.
Output
Hibernate:
insert into mkyong.stock (STOCK_CODE, STOCK_NAME)
values (?, ?)
if mutable = “false” or @Immutable is declared in class.
Output
Hibernate:
insert into mkyong.stock (STOCK_CODE, STOCK_NAME)
values (?, ?)
Mutable in class has no effect in the ‘insert’ operation.
2. Test update
Stock stock = (Stock)session.createQuery(
" from Stock where stockCode = '7277'").list().get(0);
stock.setStockName("DIALOG123");
session.saveOrUpdate(stock);
if mutable = “true” or no @Immutable is declared in class.
Output
Hibernate:
select ...from mkyong.stock stock0_
where stock0_.STOCK_CODE='7277'
Hibernate:
update mkyong.stock
set STOCK_CODE=?,STOCK_NAME=?
where STOCK_ID=?
if mutable = “false” or @Immutable is declared in class.
Output
Hibernate:
select ...from mkyong.stock stock0_
where stock0_.STOCK_CODE='7277'
Mutable in class is not allow application to update it, the ‘update’ operation will be ignore and no exception is thrown
3. Test delete
Stock stock = (Stock)session.createQuery(
" from Stock where stockCode = '7277'").list().get(0);
session.delete(stock);
if mutable = “true” (default) or no @Immutable is declared in class.
Output
Hibernate:
delete from mkyong.stock
where STOCK_ID=?
if mutable = “false” or @Immutable is declared in class.
Output
Hibernate:
delete from mkyong.stock
where STOCK_ID=?
Mutable in class has no effect in the ‘delete’ operation.
Mutable in collection
If mutable = “false” or @Immutable is declared in collection, it means the add and delete-orphan are not allow in this collection, with exception throw, only update and ‘cascade delete all’ are allow.
1. Test insert
Assume the cascade insert is enabled.
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);
if mutable = “true” (default) or no @Immutable is declared in collection.
Output
Hibernate:
insert into mkyong.stock_daily_record
(STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE)
values (?, ?, ?, ?, ?, ?)
if mutable = “false” or @Immutable is declared in collection.
Output
Exception in thread "main" org.hibernate.HibernateException:
changed an immutable collection instance:
[com.mkyong.common.Stock.stockDailyRecords#111]
Mutable in collection is not allow the ‘add’ operation, an exception will throw.
2. Test update
Assume the cascade update is enabled.
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);
if mutable = “true” (default) or no @Immutable is declared in collection.
Output
Hibernate:
update mkyong.stock_daily_record
set PRICE_CHANGE=?, ...
where DAILY_RECORD_ID=?
if mutable = “false” or @Immutable is declared in collection.
Output
Hibernate:
update mkyong.stock_daily_record
set PRICE_CHANGE=?, ...
where DAILY_RECORD_ID=?
Mutable in collection has no effect in the ‘update’ operation.
3. Test delete-orphan
Assume the cascade delete-orphan is enabled.
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);
if mutable = “true” (default) or no @Immutable is declared in collection.
Output
Hibernate:
delete from mkyong.stock_daily_record
where DAILY_RECORD_ID=?
if mutable = “false” or @Immutable is declared in collection.
Output
Exception in thread "main" org.hibernate.HibernateException:
changed an immutable collection instance:
[com.mkyong.common.Stock.stockDailyRecords#111]
Mutable in collection is not allow the ‘delete-orphan’ operation, an exception will throw.
4. Test delete
Assume the cascade delete is enabled.
Stock stock = (Stock)session.createQuery(
" from Stock where stockCode = '7277'").list().get(0);
session.saveOrUpdate(stock);
if mutable = “true” (default) or no @Immutable is declared in collection.
Output
Hibernate:
delete from mkyong.stock_daily_record
where DAILY_RECORD_ID=?
Hibernate:
delete from mkyong.stock
where STOCK_ID=?
if mutable = “false” or @Immutable is declared in collection.
Output
Hibernate:
delete from mkyong.stock_daily_record
where DAILY_RECORD_ID=?
Hibernate:
delete from mkyong.stock
where STOCK_ID=?
Mutable in collection has no effect in the ‘delete’ operation, if parent is deleted, all its child will be delete as well, even it’s mutable.
Why mutable ?
Mutable can avoid many unintentional database operation, like add, update or delete some records which shouldn’t be. In addition, according to Hibernate documentation, the mutable do has some minor performance optimizations, it’s always recommend to analysis your mapping relationship and implement the mutable as needed.
Summary
1. mutable = “false” or @Immutable is declared in class
it means the updates to this class will be ignored, but no exception is thrown, only the add and delete operation are allow.
In Class with mutable=”false” – insert=allow, delete=allow , update=not allow
2. mutable = “false” or @Immutable is declared in collection
it means the add and delete-orphan are not allow in this collection, with exception throw, only update allow. However, if cascade delete is enable, when the parent is deleted, all it’s child will be delete as well, even it is mutable.
In Collection with mutable=”false” – insert=not allow, delete-orphan=not allow, delete=allow , update=allow
Completely immutable ?
Can a class completely immutable to any actions? Yes, put a mutable=”false” to all it’s relationship (insert=not allow, delete-orphan=not allow), and a mutable=”false” to the class you want to immutable (update=not allow). Now, you have a completely immutable class, however, if the cascade delete option is enabled, when the parent of your immutable class is deleted, your immutable class will still be deleted as well.
Reference
1. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
The code example in item 4 “Test delete” contains error
…session.saveOrUpdate(stock);
but must be
… session.DELETE(stock);
Hi,
Can you please update the statement:
“If mutable = “false” or @Immutable is declared in class element, it means the updates to this class will be ignored, but no exception is thrown, only the add and delete operation are allow.”
AS
“If mutable = “false” or @Immutable is declared in class element, it means the insert,delete, updates to this class will be ignored, but no exception is thrown”
Hibernate is very helpful to improve the data base, and recommendations related to the analysis, very precise.
Your Grammar is very poor. Allow me to fix all of your grammatical errors on your site. Price is open and negotiable!
Who cares about his grammar? We are developers and care only about code. So piss off