|
數(shù)據(jù)庫中一個(gè)字段的默認(rèn)值設(shè)為0,當(dāng)用hibernate插入數(shù)據(jù)時(shí),沒有對該字段進(jìn)行操作,結(jié)果該字段居然不是0,而是空。后來google了一下,發(fā)現(xiàn)應(yīng)該在.hbm.xml文件中添加一些參數(shù)定義(示例中的紅色部分),具體如下:
<hibernate-mapping> <class name="com.tom.hibernate.EbayItem" table="EBAY_ITEM" schema="API_USER" dynamic-insert="true" dynamic-update="true"> ....... ........ </class> </hibernate-mapping>
在我們熟悉的Hibernate映射文件中也大有乾坤,很多值得我注意的地方。 在Hibernate的映射文件的class tag使用dynamic-insert,dynamic-update,可以優(yōu)化生成的SQL語句,提高SQL執(zhí)行效率,最終可以提高系統(tǒng)性能。 如,有一個(gè)User類。
public class User { /** Creates a new instance of User */ public User() { } private long id; private int age;
private String firstname; private String lastname; private Set emailAddresses; //省略getter 和setter方法 }
Hibernate映射文件(User.hbm.xml,省略了文件頭聲明)定義為: <hibernate-mapping> <class name="model.User" table="Users" > <id name="id" column="ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> <set name="emailAddresses" table="PERSON_EMAIL_ADDR"> <key column="PERSON_ID"/> <element type="string" column="EMAIL_ADDR"/> </set> </class> </hibernate-mapping> 我們寫一個(gè)測試類進(jìn)行測試UserTest。
public class UserTest extends TestCase { public UserTest(String testName) { super(testName); } private Session session; private SessionFactory sessionFactory; protected void setUp() throws Exception { sessionFactory=HibernateUtil.getSessionFactory(); session=sessionFactory.openSession(); session.getTransaction().begin(); } protected void tearDown() throws Exception { session.getTransaction().commit(); session.close(); } /** * Test of getAge method, of class model.User. */ public void testSaveUser() { System.out.println("================testSaveUser================="); User user = new User(); user.setAge(29); session.save(user); assertNotNull("id is assigned !",user.getId()); } public void testUpdateUser() { System.out.println("================testUpdateUser================="); User user = new User(); user.setAge(29); session.save(user); assertNotNull("id is assigned !",user.getId()); User _user=(User) session.get(User.class, user.getId()); _user.setFirstname("Array"); session.update(_user); } } 運(yùn)行測試后,此時(shí)會生成完整的SQL語句(注意將hibernate屬性show_sql設(shè)置成true)。
================testSaveUser================= Hibernate: insert into Users (age, firstname, lastname) values (?, ?, ?) ================testUpdateUser================= Hibernate: insert into Users (age, firstname, lastname) values (?, ?, ?) Hibernate: update Users set age=?, firstname=?, lastname=? where ID=?
如果我們在<class ...>中加上 dynamic-insert="true" dynamic-update="true",變成如下。
<class name="model.User" table="Users" dynamic-insert="true" dynamic-update="true">
再次運(yùn)行測試類,就會發(fā)現(xiàn)生成的SQL中涉及的字段只包含User類中修改的屬性所對應(yīng)的表字段。
================testSaveUser================= Hibernate: insert into Users (age) values (?) ================testUpdateUser================= Hibernate: insert into Users (age) values (?) Hibernate: update Users set firstname=? where ID=?
如果一個(gè)表的結(jié)構(gòu)很復(fù)雜,字段很多的情況下,使用dynamic-insert,dynamic-update能夠性能上的少許提升。
下面是有關(guān)其它配置的說明
Hibernate允許我們在映射文件里控制insert和update語句的內(nèi)容.比如在映射文件中<property 元素中的update屬性設(shè)置成為false,那么這個(gè)字段,將不被包括在基本的update語句中,修改的時(shí)候,將不包括這個(gè)字段了.insert同理.dynamic動態(tài)SQL語句的配置也是很常用的.下面介紹配置SQL語句的具體屬性: 1)<property>元素 insert屬性:設(shè)置為false,在insert語句中不包含這個(gè)字段,表示永遠(yuǎn)不會被插入,默認(rèn)true 2)<property>元素 update屬性:設(shè)置為false,在update語句中不包含這個(gè)字段,表示永遠(yuǎn)不會被修改,默認(rèn)true 3)<class>元素 mutable屬性:設(shè)置為false就是把所有的<property>元素的update屬性設(shè)置為了false,說明這個(gè)對象不會被更新,默認(rèn)true 4)<property>元素 dynamic-insert屬性:設(shè)置為true,表示insert對象的時(shí)候,生成動態(tài)的insert語句,如果這個(gè)字段的值是null就不會加入到insert語句當(dāng)中.默認(rèn)false 5)<property>元素 dynamic-update屬性,設(shè)置為true,表示update對象的時(shí)候,生成動態(tài)的update語句,如果這個(gè)字段的值是null就不會被加入到update語句中,默認(rèn)false 6)<class>元素 dynamic-insert屬性:設(shè)置為true,表示把所有的<property>元素的dynamic-insert屬性設(shè)置為true,默認(rèn)false 7)<class>元素 dynamic-update屬性:設(shè)置為true,表示把所有的<property>元素的dynamic-update屬性設(shè)置為true,默認(rèn)false
Hibernate生成動態(tài)SQL語句的消耗的系統(tǒng)資源(比如CPU,內(nèi)存等)是很小的,所以不會影響到系統(tǒng)的性能,如果表中包含N多字段,建議把dynamic-update屬性和insert屬性設(shè)置為true,這樣在插入和修改數(shù)據(jù)的時(shí)候,語句中只包括要插入或者修改的字段.可以節(jié)省SQL語句的執(zhí)行時(shí)間,提高程序的運(yùn)行效率.
hibernate 常用注解說明。
@content ejb3注解的API定義在javax.persistence.*包里面。 注釋說明: @Entity —— 將一個(gè)類聲明為一個(gè)實(shí)體bean(即一個(gè)持久化POJO類) @Id —— 注解聲明了該實(shí)體bean的標(biāo)識屬性(對應(yīng)表中的主鍵)。 @Table —— 注解聲明了該實(shí)體bean映射指定的表(table),目錄(catalog)和schema的名字 @Column —— 注解聲明了屬性到列的映射。該注解有如下的屬性 name 可選,列名(默認(rèn)值是屬性名) unique 可選,是否在該列上設(shè)置唯一約束(默認(rèn)值false) nullable 可選,是否設(shè)置該列的值可以為空(默認(rèn)值false) insertable 可選,該列是否作為生成的insert語句中的一個(gè)列(默認(rèn)值true) updatable 可選,該列是否作為生成的update語句中的一個(gè)列(默認(rèn)值true) columnDefinition 可選,為這個(gè)特定列覆蓋sql ddl片段(這可能導(dǎo)致無法在不同數(shù)據(jù)庫間移植) table 可選,定義對應(yīng)的表(默認(rèn)為主表) length 可選,列長度(默認(rèn)值255) precision 可選,列十進(jìn)制精度(decimal precision)(默認(rèn)值0) scale 可選,如果列十進(jìn)制數(shù)值范圍(decimal scale)可用,在此設(shè)置(默認(rèn)值0) @GeneratedValue —— 注解聲明了主鍵的生成策略。該注解有如下屬性 strategy 指定生成的策略(JPA定義的),這是一個(gè)GenerationType。默認(rèn)是GenerationType. AUTO GenerationType.AUTO 主鍵由程序控制 GenerationType.TABLE 使用一個(gè)特定的數(shù)據(jù)庫表格來保存主鍵 GenerationType.IDENTITY 主鍵由數(shù)據(jù)庫自動生成(主要是自動增長類型) GenerationType.SEQUENCE 根據(jù)底層數(shù)據(jù)庫的序列來生成主鍵,條件是數(shù)據(jù)庫支持序列。(這個(gè)值要與generator一起使用) generator 指定生成主鍵使用的生成器(可能是orcale中的序列)。 @SequenceGenerator —— 注解聲明了一個(gè)數(shù)據(jù)庫序列。該注解有如下屬性 name 表示該表主鍵生成策略名稱,它被引用在@GeneratedValue中設(shè)置的“gernerator”值中 sequenceName 表示生成策略用到的數(shù)據(jù)庫序列名稱。 initialValue 表示主鍵初始值,默認(rèn)為0. allocationSize 每次主鍵值增加的大小,例如設(shè)置成1,則表示每次創(chuàng)建新記錄后自動加1,默認(rèn)為50. @GenericGenerator —— 注解聲明了一個(gè)hibernate的主鍵生成策略。支持十三種策略。該注解有如下屬性 name 指定生成器名稱 strategy 指定具體生成器的類名(指定生成策略)。 parameters 得到strategy指定的具體生成器所用到的參數(shù)。 其十三種策略(strategy屬性的值)如下: 1.native 對于orcale采用Sequence方式,對于MySQL和SQL Server采用identity(處境主鍵生成機(jī)制), native就是將主鍵的生成工作將由數(shù)據(jù)庫完成,hibernate不管(很常用) 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "native") 2.uuid 采用128位的uuid算法生成主鍵,uuid被編碼為一個(gè)32位16進(jìn)制數(shù)字的字符串。占用空間大(字符串類型)。 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "uuid") 3.hilo 要在數(shù)據(jù)庫中建立一張額外的表,默認(rèn)表名為hibernate_unque_key,默認(rèn)字段為integer類型,名稱是next_hi(比較少用) 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "hilo") 4.assigned 在插入數(shù)據(jù)的時(shí)候主鍵由程序處理(很常用),這是<generator>元素沒有指定時(shí)的默認(rèn)生成策略。等同于JPA中的AUTO。 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "assigned") 5.identity 使用SQL Server和MySQL的自增字段,這個(gè)方法不能放到Oracle中,Oracle不支持自增字段,要設(shè)定sequence(MySQL和SQL Server中很常用)。等同于JPA中的IDENTITY 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "identity") 6.select 使用觸發(fā)器生成主鍵(主要用于早期的數(shù)據(jù)庫主鍵生成機(jī)制,少用) 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "select") 7.sequence 調(diào)用謹(jǐn)慎數(shù)據(jù)庫的序列來生成主鍵,要設(shè)定序列名,不然hibernate無法找到。 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "sequence", parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") }) 8.seqhilo 通過hilo算法實(shí)現(xiàn),但是主鍵歷史保存在Sequence中,適用于支持Sequence的數(shù)據(jù)庫,如Orcale(比較少用) 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "seqhilo", parameters = { @Parameter(name = "max_lo", value = "5") }) 9.increnment 插入數(shù)據(jù)的時(shí)候hibernate會給主鍵添加一個(gè)自增的主鍵,但是一個(gè)hibernate實(shí)例就維護(hù)一個(gè)計(jì)數(shù)器,所以在多個(gè)實(shí)例運(yùn)行的時(shí)候不能使用這個(gè)方法。 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "increnment") 10.foreign 使用另一個(gè)相關(guān)的對象的主鍵。通常和<one-to-one>聯(lián)合起來使用。 例:@Id @GeneratedValue(generator = "idGenerator") @GenericGenerator(name = "idGenerator", strategy = "foreign", parameters = { @Parameter(name = "property", value = "info") }) Integer id; @OneToOne EmployeeInfo info; 11.guid 采用數(shù)據(jù)庫底層的guid算法機(jī)制,對應(yīng)MySQL的uuid()函數(shù),SQL Server的newid()函數(shù),ORCALE的rawtohex(sys_guid())函數(shù)等 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "guid") 12.uuid.hex 看uudi,建議用uuid替換 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "uuid.hex") 13.sequence-identity sequence策略的擴(kuò)展,采用立即檢索策略來獲取sequence值,需要JDBC3.0和JDK4以上(含1.4)版本 例:@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "sequence-identity", parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") }) @OneToOne 設(shè)置一對一個(gè)關(guān)聯(lián)。cascade屬性有五個(gè)值(只有CascadeType.ALL好用?很奇怪),分別是CascadeType.PERSIST(級聯(lián)新建),CascadeType.REMOVE(級聯(lián)刪除),CascadeType.REFRESH(級聯(lián)刷新),CascadeType.MERGE(級聯(lián)更新),CascadeType.ALL(全部四項(xiàng)) 方法一 主表: ?@OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn public 從表類 get從表類(){return 從表對象} 從表:沒有主表類。 注意:這種方法要求主表與從表的主鍵值想對應(yīng)。 方法二 主表:?@OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="主表外鍵") //這里指定的是數(shù)據(jù)庫中的外鍵字段。 public 從表類 get從表類(){return 從表類} 從表:@OneToOne(mappedBy = "主表類中的從表屬性")//例主表User中有一個(gè)從表屬性是Heart類型的heart,這里就填heart public 主表類 get主表類(){return 主表對象} 注意:@JoinColumn是可選的。默認(rèn)值是從表變量名+"_"+從表的主鍵(注意,這里加的是主鍵。而不是主鍵對應(yīng)的變量)。 方法三 主表:@OneToOne(cascade=CascadeType.ALL) @JoinTable( name="關(guān)聯(lián)表名", joinColumns = @JoinColumn(name="主表外鍵"), inverseJoinColumns = @JoinColumns(name="從表外鍵") ) 從表:@OneToOne(mappedBy = "主表類中的從表屬性")//例主表User中有一個(gè)從表屬性是Heart類型的heart,這里就填heart public 主表類 get主表類(){return 主表對象} @ManyToOne 設(shè)置多對一關(guān)聯(lián) 方法一 @ManyToOne(cascade={CasCadeType.PERSIST,CascadeType.MERGE}) @JoinColumn(name="外鍵") public 主表類 get主表類(){return 主表對象} 方法二 @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}) @JoinTable(name="關(guān)聯(lián)表名", joinColumns = @JoinColumn(name="主表外鍵"), inverseJoinColumns = @JoinColumns(name="從表外鍵") ) @OneToMany 設(shè)置一對多關(guān)聯(lián)。cascade屬性指定關(guān)聯(lián)級別,參考@OneToOne中的說明。fetch指定是否延遲加載,值為FetchType.LAZY表示延遲,為FetchType.EAGER表示立即加載 方法一 使用這種配置,在為“一端”添加“多端”時(shí),不會修改“多端”的外鍵。在“一端”加載時(shí),不會得到“多端”。如果使用延遲加載,在讀“多端”列表時(shí)會出異常,立即加載在得到多端時(shí),是一個(gè)空集合(集合元素為0)。 “一端”配置 @OneToMany(mappedBy="“多端”的屬性") public List<“多端”類> get“多端”列表(){return “多端”列表} “多端”配置參考@ManyToOne. 方法二 “一端”配置 @OneToMany(mappedBy="“多端”的屬性") @MapKey(name="“多端”做為Key的屬性") public Map<“多端”做為Key的屬性的類,主表類> get“多端”列表(){return “多端”列表} “多端”配置參考@ManyToOne. 方法三 使用這種配置,在為“一端”添加“多端”時(shí),可以修改“多端”的外鍵。 “一端”配置 @OneToMany @JoinColumn(name="“多端外鍵") public List<“多端類> get“多端列表(){return “多端列表} “多端配置參考@ManyToOne.
|