单个持久化类与单个数据库表之间进行映射的技巧:
主要解决以下问题:
持久化类的属性没有相关的setXXX()和getXXX()方法;
持久化类的属性在数据库中没有对应的字段,或者数据库中的字段在持久化类中没有对应的属性;
控制Hibernate生成的insert和update语句;
设置从持久化类映射到数据库表,以及持久化类的属性映射到数据库表的字段的命名策略;
一.持久化类的属性及访问方法
1 、getXXX() setXXX() 的产生是为了控制属性的读权限和改权限;
2 、java中的基本类型和包装类型对应着相同的Hibernate映射类型;
3 、在持久化类中,java基本类型和包装类型比较:基本类型操作方便,可以直接进行运算,包装类不行;基本数据类型不能表达NULL值。(java包装类型与sql数据类型有更直接的对应关系)
二.Hibernate访问持久化类属性的策略
1.在对象--关系映射文件中,<property>元素的access属性用于指定访问持久化类的属性的方法。
(1)property 默认值。表示Hibernate通过相应的setXXX() 和 getXXX()方法访问属性。
(2)field 表明Hibernate运用java反射机制直接访问类的属性。(类中没有提供属性的setXXX() 和 getXXX()方法)
2. 在Customer类的setSex()方法中加入数据验证逻辑。
public
void
setSex(
char
sex){
if
(sex!=
'F'
&& sex!=
'M'
){
throw
new
IllegalArgumentException(
"Invalid Sex"
);
}
this
.sex=sex;
}
setSex(
char
sex)
有两个调用者:
java
应用程序和
Hibernate
。
Java
应用程序调用时,参数可能来自用户界面输入的数据,需要验证;而
hibernate
调用时,参数值来自数据库读出的数据,通常是合法的,不需要验证。
解决这一个矛盾的方法是:
把映射文件中的
sex
属性的
<property>
元素的
access
属性设为
”field”
这样
hinernate
就会直接访问
Customer
实例的
sex
属性,而不调用
set
和
get
方法
一个例子:
1 数据库部分:
drop
database
if
exists
SAMPLEDB;
create
database
SAMPLEDB;
use
SAMPLEDB;
create
table
DICTIONARIES (
ID
bigint
not
null
,
TYPE
varchar
(15),
TYPE_KEY
varchar
(15),
VALUE
varchar
(128),
primary
key
(ID)
);
create
table
ORDERS (
ID
bigint
not
null
,
ORDER_NUMBER
varchar
(15),
PRICE
double
precision
,
CUSTOMER_ID
bigint
not
null
,
primary
key
(ID)
);
create
table
CUSTOMERS (
ID
bigint
not
null
,
NAME
varchar
(15),
SEX
char
(1),
`CUSTOMER DESCRIPTION` text,
primary
key
(id)
);
alter
table
ORDERS
add
index
IDX_CUSTOMER (CUSTOMER_ID),
add
constraint
FK_CUSTOMER
foreign
key
(CUSTOMER_ID)
references
CUSTOMERS (id);
注意:
`CUSTOMER DESCRIPTION` sql
引用标识符
(
数据库中的字段含有空格)
2 java类:
Customer.java
package
mypack;
import
java.io.Serializable;
import
java.util.HashSet;
import
java.util.Iterator;
import
java.util.Set;
import
java.util.StringTokenizer;
public
class
Customer
implements
Serializable {
private
Long
id
;
private
String
firstName
;
private
String
lastName
;
private
char
sex
;
private
Set
orders
=
new
HashSet();
private
double
avgPrice
;
private
double
totalPrice
;
private
String
description
;
public
Customer() {
//
TODO
Auto-generated constructor stub
}
public
Customer(String lastName, String firstName,
char
sex,
HashSet orders, String description) {
//
TODO
Auto-generated constructor stub
this
.
lastName
= lastName;
this
.
firstName
= firstName;
this
.
sex
= sex;
this
.
orders
= orders;
this
.
description
= description;
}
public
double
getAvgPrice() {
return
avgPrice
;
}
public
String getDescription() {
return
description
;
}
public
void
setDescription(String description) {
this
.
description
= description;
}
public
String getFirstName() {
return
firstName
;
}
public
Long getId() {
return
id
;
}
public
void
setId(Long id) {
this
.
id
= id;
}
public
String getLastName() {
return
lastName
;
}
public
Set getOrders() {
return
orders
;
}
public
void
setOrders(Set orders) {
this
.
orders
= orders;
}
public
char
getSex() {
return
sex
;
}
public
void
setSex(
char
sex) {
if
(sex !=
'F'
&& sex !=
'M'
) {
throw
new
IllegalArgumentException(
"Invalid Sex"
);
}
this
.
sex
= sex;
}
public
double
getTotalPrice() {
return
totalPrice
;
}
public
void
setTotalPrice(
double
totalPrice) {
this
.
totalPrice
= totalPrice;
}
public
String getName() {
return
firstName
+
" "
+
lastName
;
}
public
void
setName(String name) {
StringTokenizer t =
new
StringTokenizer(name);
firstName
= t.nextToken();
lastName
= t.nextToken();
}
public
void
caculatePrice() {
double
avgPrice = 0.0;
double
totalPrice = 0.0;
int
count = 0;
Iterator it = getOrders().iterator();
while
(it.hasNext()) {
Order order = (Order) it.next();
totalPrice += order.getOrderPrice();
count++;
}
avgPrice = totalPrice / count;
setAvgPrice(avgPrice);
}
public
void
setAvgPrice(
double
avgPrice) {
this
.
avgPrice
= avgPrice;
}
}
Order.java 类
package
mypack;
import
java.io.Serializable;
public
class
Order
implements
Serializable
{
private
Long
id
;
private
double
orderPrice
;
private
String
order_number
;
private
double
price
;
private
Customer
customer
;
public
Order(String order_number,
double
price, Customer customer) {
//
TODO
Auto-generated constructor stub
this
.
order_number
= order_number;
this
.
price
= price;
this
.
customer
= customer;
}
public
Customer getCustomer() {
return
customer
;
}
public
void
setCustomer(Customer customer) {
this
.
customer
= customer;
}
public
String getOrder_number() {
return
order_number
;
}
public
void
setOrder_number(String order_number) {
this
.
order_number
= order_number;
}
public
double
getPrice() {
return
price
;
}
public
void
setPrice(
double
price) {
this
.
price
= price;
}
public
double
getOrderPrice() {
return
orderPrice
;
}
public
void
setOrderPrice(
double
orderPrice) {
this
.
orderPrice
= orderPrice;
}
public
Long getId() {
return
id
;
}
private
void
setId(Long id) {
this
.
id
= id;
}
}
Dictionary.java
package
mypack;
import
java.io.Serializable;
public
class
Dictionary
implements
Serializable {
private
Long
id
;
private
String
type
;
private
String
type_key
;
private
String
value
;
public
Dictionary() {
}
public
Dictionary(String type, String type_key, String value) {
this
.
type
= type;
this
.
type_key
= type_key;
this
.
value
= value;
}
public
Long getId() {
return
id
;
}
private
void
setId(Long id) {
this
.
id
= id;
}
public
String getType() {
return
type
;
}
public
void
setType(String type) {
this
.
type
= type;
}
public
String getType_key() {
return
type_key
;
}
public
void
setType_key(String type_key) {
this
.
type_key
= type_key;
}
public
String getValue() {
return
value
;
}
public
void
setValue(String value) {
this
.
value
= value;
}
}
3 映射文件部分
Customer.hbm.xml
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<!
DOCTYPE
hibernate-mapping
PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<
hibernate-mapping
>
<
class
name
=
"mypack.Customer"
table
=
"customers"
catalog
=
"sampledb"
dynamic-insert="true" dynamic-update="true"
lazy
=
"false"
>
<!--
dynamic-insert="true" dynamic-update="true"
分别表示
insert
语句中仅包含所有取值不为空的字段
和
只有字段发生变化时才会包含到
update
语句中
-->
<
id
name
=
"id"
type
=
"long"
>
<
column
name
=
"ID"
/>
<
generator
class
=
"increment"
/>
</
id
>
<
property
name
=
"name"
type
=
"string"
>
<
column
name
=
"NAME"
/>
</
property
>
<
property
name
=
"sex"
type
=
"character"
access="field"
>
<!--
直接取设属性值
-->
<
column
name
=
"SEX"
length
=
"1"
/>
</
property
>
<
property
name
=
"description"
type
=
"text"
>
<
column
name
=
"
`CUSTOMER DESCRIPTION`
"
/>
</
property
>
<
property
name
=
"totalPrice"
formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)"
>
<!—
数据库中不含有次字段,它对应一个
sql
语句的结果
-->
</
property
>
<
set
name
=
"orders"
inverse
=
"true"
cascade
=
"save-update"
>
<
key
column
=
"CUSTOMER_ID"
></
key
>
<
one-to-many
class
=
"mypack.Order"
/>
</
set
>
</
class
>
</
hibernate-mapping
>
Order.hbm.xml
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<!
DOCTYPE
hibernate-mapping
PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<
hibernate-mapping
>
<
class
name
=
"mypack.Order"
table
=
"ORDERS"
catalog
=
"sampledb"
dynamic-insert
=
"true"
dynamic-update
=
"true"
>
<
id
name
=
"id"
type
=
"long"
>
<
column
name
=
"ID"
/>
<
generator
class
=
"increment"
/>
</
id
>
<
property
name
=
"order_number"
>
</
property
>
<
property
name
=
"price"
></
property
>
<
many-to-one
name
=
"customer"
column
=
"CUSTOMER_ID"
class
=
"mypack.Customer"
>
</
many-to-one
>
</
class
>
</
hibernate-mapping
>
Dictionary.hbm.xml
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<!
DOCTYPE
hibernate-mapping
PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<
hibernate-mapping
>
<
class
name
=
"mypack.Dictionary"
table
=
"DICTIONARIES"
catalog
=
"sampledb"
mutable
=
"false"
lazy
=
"false"
>
<!--
整个实例不能被更新
-->
<
id
name
=
"id"
type
=
"long"
>
<
column
name
=
"ID"
/>
<
generator
class
=
"increment"
/>
</
id
>
<
property
name
=
"type"
type
=
"string"
access
=
"field"
></
property
>
<
property
name
=
"type_key"
type
=
"string"
access
=
"field"
></
property
>
<
property
name
=
"value"
type
=
"string"
access
=
"field"
></
property
>
</
class
>
</
hibernate-mapping
>
4 测试类
package
mypack;
import
java.util.HashSet;
import
org.hibernate.Session;
import
org.hibernate.Transaction;
import
sessionFactory.HibernateSessionFactory;
public
class
BusinessService {
public
Customer loadCustomer(Long customer_id)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
Customer customer = (Customer) session.load(Customer.
class
,
customer_id);
tr.commit();
return
customer;
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
saveCustomer(Customer customer)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
session.save(customer);
tr.commit();
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
loadAndUpdateCustomer(Long customerId)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
Customer customer = (Customer) session.load(Customer.
class
,
customerId);
customer.setDescription(
"A lovely customer!"
);
tr.commit();
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
updateCustomer(Customer customer)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
session.update(customer);
tr.commit();
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
saveDictionary(Dictionary dictionary)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
session.save(dictionary);
tr.commit();
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
updateDictionary(Dictionary dictionary)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
session.update(dictionary);
tr.commit();
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
Dictionary loadDictionary(Long dictionary_id)
throws
Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tr =
null
;
try
{
tr = session.beginTransaction();
Dictionary dictionary = (Dictionary) session.load(Dictionary.
class
,
dictionary_id);
tr.commit();
return
dictionary;
}
catch
(Exception e) {
//
TODO
: handle exception
if
(tr !=
null
) {
tr.rollback();
}
throw
e;
}
finally
{
session.close();
}
}
public
void
printCustomer(Customer customer) {
System.
out
.println(
"name:"
+ customer.getName());
System.
out
.println(
"sex:"
+ customer.getSex());
System.
out
.println(
"description:"
+ customer.getDescription());
System.
out
.println(
"avgPrice:"
+ customer.getAvgPrice());
System.
out
.println(
"totalPrice:"
+ customer.getTotalPrice());
}
public
void
printDictionary(Dictionary dictionary) {
System.
out
.println(
"type:"
+ dictionary.getType());
System.
out
.println(
"key:"
+ dictionary.getType_key());
System.
out
.println(
"value:"
+ dictionary.getValue());
}
public
void
test()
throws
Exception {
// Customer customer = new Customer("Laosan", "Zhang", 'M', new
// HashSet(),
// "A good citizen!");
// Order order1 = new Order("Order001", 100, customer);
// Order order2 = new Order("Order002", 200, customer);
// customer.getOrders().add(order1);
// customer.getOrders().add(order2);
//
// saveCustomer(customer);
//
// customer = new Customer("Laowu", "Wang", 'M', new HashSet(), null);
// saveCustomer(customer);
//
// customer = loadCustomer(new Long(1));
//
// customer.setDescription("An honest customer!");
// updateCustomer(customer);
//
// printCustomer(customer);
//
// loadAndUpdateCustomer(new Long(1));
Dictionary dictionary =
new
Dictionary(
"SEX"
,
"M"
,
"MALE"
);
saveDictionary(dictionary);
printDictionary(dictionary);
dictionary = loadDictionary(
new
Long(1));
dictionary.setValue(
"MAN"
);
updateDictionary(dictionary);
dictionary = loadDictionary(
new
Long(1));
printDictionary(dictionary);
}
public
static
void
main(String[] args)
throws
Exception {
BusinessService b =
new
BusinessService();
b.test();
}
}
5 问题:
在测试 Customer 和 Dictionary的load 方法时报错:
could not initialize proxy - the owning Session was closed
解决办法:把对应类的映射文件中加入
lazy= "false"
限制(
class
元素中)