1. 程式人生 > >Hibernate關聯關係之一對一關聯關係的CRUD操作

Hibernate關聯關係之一對一關聯關係的CRUD操作

說明:本文註釋的不是很多,只是功能上能簡單的基本達到。要看詳細的說明可參考另一篇博文超詳細的Hibernate關聯關係之雙向的一對多關聯關係的CRUD操作————學習至黑馬程式設計師視訊教程。。當然,one-to-one , many-to-one , many-to-many 這幾個標籤的屬性都各不相同,當用到的時還是需要去檢視相關文件的。

=================================================================

1.專案結構:

============================

2.pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.lin</groupId>
  <artifactId>Hibernate_OneToOne</artifactId>
  <version>0.0.1-SNAPSHOT</version>

<dependencies>
		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>3.6.10.Final</version>
		</dependency>
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-entitymanager</artifactId>
		    <version>3.6.10.Final</version>
		</dependency>

		<!-- MySQL驅動包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.41</version>
		</dependency>
		
		<!-- slf4j -->
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-nop</artifactId>
		    <version>1.7.25</version>
		    <scope>test</scope>
		</dependency>
		
		
		<!-- jstl、servlet-api、junit -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit-dep</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

</project>

============================

3.實體類跟其對應的對映檔案:

User.java

package com.lin.domain;

import java.io.Serializable;

/**
 * 使用者實體類
 * */

public class User implements Serializable{
	private static final long serialVersionUID = 1L;
	
	private Long userId;
	private String userName;
	private String password;
	
	//一個使用者只能對應一個身份證,一個身份證只能被一個使用者擁有。所以使用者和身份證是一對一關聯關係。
	private Card card;
	
	public User() {
		super();
	}
	public User(Long userId, String userName, String password) {
		super();
		this.userId = userId;
		this.userName = userName;
		this.password = password;
	}
	public Long getUserId() {
		return userId;
	}
	public void setUserId(Long userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Card getCard() {
		return card;
	}
	public void setCard(Card card) {
		this.card = card;
	}
	
	@Override
	public String toString() {
		return "User [userId=" + userId + ", userName=" + userName
				+ ", password=" + password + "]";
	}
	
	
}

User.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 package="com.lin.domain">
	
	<!-- name指定持久化類的類名,table指定資料表的表名 -->
	<class name="User" table="table_user">
		<id name="userId" column="user_id">
			<generator class="native"/>
		</id>
		<property name="userName" column="user_name"></property>
		<property name="password" column="password"></property>
		
		<!--對映關聯屬性card。cascade="all"表示級聯儲存User物件關聯的Card物件-->
		 <one-to-one name="card" class="Card" cascade="all" property-ref="user"></one-to-one>
	</class>
	
</hibernate-mapping>

Card.java

package com.lin.domain;

import java.io.Serializable;

/**
 * 身份證實體類
 * */

public class Card implements Serializable{
	private static final long serialVersionUID = 1L;
	
	private Long cardId;
	private String cardNumber;
	
	//一個使用者只能對應一個身份證,一個身份證只能被一個使用者擁有。所以使用者和身份證是一對一關聯關係。
	private User user;
	
	public Card() {
		super();
	}
	public Card(Long cardId, String cardNumber) {
		super();
		this.cardId = cardId;
		this.cardNumber = cardNumber;
	}
	public Long getCardId() {
		return cardId;
	}
	public void setCardId(Long cardId) {
		this.cardId = cardId;
	}
	public String getCardNumber() {
		return cardNumber;
	}
	public void setCardNumber(String cardNumber) {
		this.cardNumber = cardNumber;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	
	@Override
	public String toString() {
		return "Card [cardId=" + cardId + ", cardNumber=" + cardNumber + "]";
	}
	

}

Card.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 package="com.lin.domain">
	
	<!-- name指定持久化類的類名,table指定資料表的表名 -->
	<class name="Card" table="table_card">
		<id name="cardId" column="card_id">
			<generator class="native"/>
		</id>
		<property name="cardNumber" column="card_number"></property>
		
		<many-to-one name="user" class="User" unique="true">
			<!--column屬性指定用來進行關聯的外來鍵列列名-->
			<column name="user_id"></column>
		</many-to-one>
		
	</class>
	
</hibernate-mapping>

============================

4.hibernate.cfg.xml

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

<!-- 
	Hibernate配置檔案包含了連線持久層與對映檔案所需的基本資訊。
	(Hibernate配置檔案主要用來配置資料庫連線以及Hibernate執行時所需的各個屬性的值。)

 -->
	
<hibernate-configuration>

	<session-factory>
		<!-- 資料庫連線設定 -->
		<!-- 配置資料庫JDBC驅動 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 配置資料庫連線URL -->
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
		<!-- 配置資料庫使用者名稱 -->
		<property name="hibernate.connection.username">root</property>
		<!-- 配置資料庫密碼 -->
		<property name="hibernate.connection.password">000000</property>
		<!-- 配置JDBC內建連線池 -->
		<property name="connection.pool_size">1</property>
		<!-- 配置資料庫方言 -->
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- 配置Hibernate採用何種方式生成DDL語句 -->
		<!-- update表示檢測實體類的對映配置和資料庫的表結構是否一致 -->
		<property name="hibernate.hbm2ddl.auto">update</property>		
		<!-- 輸出執行時生成的SQL語句 -->
		<property name="show_sql">true</property>
		
		<!-- 列出所有的對映檔案 -->
		<mapping resource="hibernate/mappings/User.hbm.xml" />
		<mapping resource="hibernate/mappings/Card.hbm.xml" />
	</session-factory>

</hibernate-configuration>

============================

5.hibernate工具類:

HibernateUtil.java

package com.lin.utils;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

	private static SessionFactory sessionFactory;
	private static Configuration configuration;
	//建立執行緒區域性變數threadLocal,用來儲存Hibernate的Session
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
	
	//使用靜態程式碼塊初始化Hibernate
	static{
		try{
			//如果不指定hibernate的配置檔案位置,那麼它會預設到classpath路徑下查詢名為hibernate.cfg.xml的檔案
			Configuration cfg = new Configuration().configure("/hibernate/hibernate.cfg.xml");
			//建立SessionFactory
			sessionFactory = cfg.buildSessionFactory();
		}catch(Throwable ex){
			throw new ExceptionInInitializerError(ex);
		}
	}
	
	//獲得SessionFactory
	public static SessionFactory getSessionFactory(){
		return sessionFactory;
	}
	
	
	//獲得ThreadLocal物件管理的Session例項
	public static Session getSession() throws HibernateException {
		Session session = (Session)threadLocal.get();
		if(session == null || session.isOpen()){
			if(sessionFactory == null){
				rebuildSessionFactory();
			}
			//通過SessionFactory物件建立Session物件
			session = (sessionFactory != null)?sessionFactory.openSession():null;
			//將新開啟的Session例項儲存到執行緒區域性變數threadLocal中
			threadLocal.set(session);
		}
		
		return session;
	}
	
	//關閉Session例項
	public static void closeSession() throws HibernateException {
		//從執行緒區域性變數threadLocal中獲取之前存入的Session例項
		Session session = (Session)threadLocal.get();
		threadLocal.set(null);
		if(session != null){
			session.close();
		}
	}
	
	
	//重建SessionFactory
	public static void rebuildSessionFactory() {
		try{
			configuration.configure("/hibernate/hibernate.cfg.xml");
			sessionFactory = configuration.buildSessionFactory();
		}catch(Exception e){
			System.out.println("Error Creating SessionFactory ");
			e.printStackTrace();
		}
	}
	
	
	//關閉快取和連線池
	public static void shutdown(){
		getSessionFactory().close();
	}
	
	public static void main(String[] args){
		HibernateUtil.getSession();
	}
}

============================

6.一對一關聯關係的CRUD操作:

這邊測試的時候有遇到一個問題,就是插入資料的時候,明明在many-to-one 中設定了unique,該外來鍵欄位還是可以重複的。難道要在資料庫建表的時候設定唯一約束?(我這裡的表是通過配置好對映檔案後,由Hibernate自動建立表的。。還望大神指教啊,,,)

HibernateOneToOneTest.java

package com.lin.test;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.lin.domain.Card;
import com.lin.domain.User;
import com.lin.utils.HibernateUtil;

/**
 * 一對一關聯對映的CRUD操作。
 * */

public class HibernateOneToOneTest {

	/**
	 * 級聯儲存操作1(儲存使用者,級聯儲存身份證)
	 * 	  找到User的對映檔案,在one-to-one標籤上新增屬性 cascade="all"即可。
	 * 
	 * 級聯儲存操作2(儲存身份證,級聯儲存使用者)
	 * 	  找到Card的對映檔案,在many-to-one標籤上新增屬性 cascade="save-update"即可。
	 * */
	@Test
	public void saveTest1(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		User user = new User();
		user.setUserName("林6");
		user.setPassword("123456");
		
		Card card = new Card();
		card.setCardNumber("350111111111111111");
		
		user.setCard(card);
		card.setUser(user);
		
//		session.save(user);
		session.save(card);
		
		tx.commit();
		session.close();
	}
	
	/**
	 * 測試用同一個身份證去關聯多個使用者
	 * (這裡的測試是能新增進去的,因為many-to-one一方已經加了unique約束,不知道為什麼還是新增進去)
	 * */
	@Test
	public void saveTest2(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		User user = (User) session.get(User.class,1L);
		
		Card card = new Card();
		card.setCardNumber("350111111111111111");
		
		card.setUser(user);
		
		session.save(card);
		
		tx.commit();
		session.close();
	}
	
	/**
	 * 刪除操作
	 * (我這裡測試的要找到User的對映檔案中的one-to-one標籤設定 property-ref="user"後方可級聯刪除資料)
	 * */
	@Test
	public void deleteTest(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		//根據id查詢使用者
		User user = (User) session.get(User.class, 3L);
		
		//刪除使用者
		session.delete(user);
		
		
		tx.commit();
		session.close();
	}
	
	/**
	 * 更新操作
	 * (僅修改了使用者關聯的身份的資訊)
	 * */
	@Test
	public void updateTest(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		//根據id查詢使用者
		User user = (User) session.get(User.class, 2L);
		
		//更新使用者關聯的身份證資訊
		user.getCard().setCardNumber("350000000000000000");
		
		session.update(user);
		
		tx.commit();
		session.close();
	}
	
	/**
	 * 更新操作
	 * (僅修改了使用者的資訊)
	 * */
	@Test
	public void updateTest2(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
		//根據id查詢使用者
		User user = (User) session.get(User.class, 2L);
		user.setUserName("小楊");
		
		session.update(user);
		
		tx.commit();
		session.close();
	}
	
	/**
	 * 查詢操作
	 * (物件導航查詢)
	 * */
	@Test
	public void selectTest(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		
//		String HQL = "from User where userId= ?";
		String HQL = "from User where userId = :userId";
//		Query query = session.createQuery(HQL).setLong(0, 2L);
//		Query query = session.createQuery(HQL).setLong("userId", 2L);
//		Query query = session.createQuery(HQL).setParameter(0, 2L);
		Query query = session.createQuery(HQL).setParameter("userId", 2L);
		
		//執行完查詢後,就發起了兩個查詢(把關聯物件也查出來了)
		User user = (User) query.uniqueResult();

		System.out.println(user);
		System.out.println(user.getCard());
		
		
		tx.commit();
		session.close();
	}
	
}