主键关联的重点是关联的两个表共享一个主键值。本例中采用,一个单位在网上的一个系统中注册会员。
1,会员数据保存在会员表company中,每个会员的登录账号保存在表login中;
2,一个会员只有一个登录账号,一个登录账号只属于一个会员,两表是一对一的对应关系;
company表如下:
生成company表的sql语句如下:
CREATE TABLE `company` (
`ID` int(4) NOT NULL AUTO_INCREMENT ,
`COMPANYNAME` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`LINKMAN` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`TELEPHONE` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`EMAIL` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`ID`)
)
login表如下:
生成login表的sql语句如下:
<pre name="code" class="sql">CREATE TABLE `login` (
`ID` int(4) NOT NULL ,
`LOGINNAME` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`LOGINPWD` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`ID`)
)
外键关联的重点是:两个表各自有不同的主键,但是其中一个表有一个外键引用另一个表的主键。即非主键是别人的主键就是该表的外键。
这个例子中:
1,客户(Client)和客户地址(Address)是外键关联的一对一关系,分别对应client表换个address表。
2,Client类在映射文件中的client_address为外键引用Address类的对应表中的主键,咋一看书多对一关系,但是在Client类对应的映射文件设置多对一对应的属性client_address时,设置了unique的值为true,即这个外键是唯一的,即一对一关系。
client表如下:
生成client表的sql语言:
CREATE TABLE `client` (
`ID` int(4) NOT NULL AUTO_INCREMENT ,
`CLIENTNAME` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`PHONE` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`EMAIL` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`CLIENTADDRESSID` int(4) NULL DEFAULT NULL ,
PRIMARY KEY (`ID`),
FOREIGN KEY (`CLIENTADDRESSID`) REFERENCES `address` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `CLIENTADDRESSID` (`CLIENTADDRESSID`) USING BTREE
)
注意:这里的CLIENTADDRESSID是外键,client表也要设置外键
address表如下:
CREATE TABLE `address` (
`ID` int(4) NOT NULL AUTO_INCREMENT ,
`PROVINCE` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`CITY` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`STREET` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`ZIPCODE` char(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`ID`)
)
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">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<property name="connection.url">jdbc:mysql://localhost:3306/onetoone</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- 显示sql语句 -->
<property name="hibernate.show_sql">true </property>
<property name="format_sql">true</property><!-- 让输出的sql语句格式化 -->
<mapping resource="com/hust/javabeans/Address.hbm.xml" />
<mapping resource="com/hust/javabeans/Client.hbm.xml" />
<mapping resource="com/hust/javabeans/Company.hbm.xml" />
<mapping resource="com/hust/javabeans/Login.hbm.xml" />
</session-factory>
</hibernate-configuration>
一对一主键双向关联:
Company.java
package com.hust.javabeans;
import java.io.Serializable;
public class Company implements Serializable {
/**
*
*/
private Integer id;
private String companyname;
private String linkman;
private String telephone;
private String email;
private Login login; //关联另外一个类,即保证Company对象中有Login对象的信息,体现一对一关联
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCompanyname() {
return companyname;
}
public void setCompanyname(String companyname) {
this.companyname = companyname;
}
public String getLinkman() {
return linkman;
}
public void setLinkman(String linkman) {
this.linkman = linkman;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Login getLogin() {
return login;
}
public void setLogin(Login login) {
this.login = login;
}
}
Login.java
package com.hust.javabeans;
import java.io.Serializable;
public class Login implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String loginname;
private String loginpwd;
private Company company; //关联另外一个类,即保证Login对象中有Company对象的信息,体现一对一关联
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getLoginpwd() {
return loginpwd;
}
public void setLoginpwd(String loginpwd) {
this.loginpwd = loginpwd;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Company.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="com.hust.javabeans.Company" table="company">
<id column="ID" name="id" type="integer">
<generator class="identity"></generator>
</id>
<property name="companyname" column="COMPANYNAME" type="string"></property>
<property name="linkman" column="LINKMAN" type="string"></property>
<property name="telephone" column="TELEPHONE" type="string"></property>
<property name="email" column="EMAIL" type="string"></property>
<!-- 映射Company与Login的一对一主键关联 -->
<one-to-one name="login" class="com.hust.javabeans.Login" cascade="all" lazy="false" fetch="join" outer-join="true"></one-to-one>
</class>
</hibernate-mapping>
Login.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="com.hust.javabeans.Login" table="login">
<!-- 使用外键生成机制(foreign),引用表company的主键作为login表的主键值 ,定义了外键的生成策略,这样可以在级联插入时保持company的主键和login的外键(也是主键)相同。-->
<id name="id" column="ID" type="integer">
<generator class="foreign">
<param name="property">company</param>
</generator>
</id>
<property name="loginname" column="LOGINNAME" type="string"></property>
<property name="loginpwd" column="LOGINPWD" type="string"></property>
<!-- 映射Company与Login的一对一主键关联 -->
<one-to-one name="company" class="com.hust.javabeans.Company" constrained="true"></one-to-one><!-- constrained="true"表示Login引用了company的主键作为外键 -->
</class>
</hibernate-mapping>
一对一外键双向关联:
Client.java
package com.hust.javabeans;
import java.io.Serializable;
public class Client implements Serializable {
private Integer id;
private String clientname;
private String phone;
private String email;
private Address client_address; //关联另一个类
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getClientname() {
return clientname;
}
public void setClientname(String clientname) {
this.clientname = clientname;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Address getClient_address() {
return client_address;
}
public void setClient_address(Address client_address) {
this.client_address = client_address;
}
}
Address.java
package com.hust.javabeans;
import java.io.Serializable;
public class Address implements Serializable {
private Integer id;
private String province;
private String city;
private String street;
private String zipcode;
private Client address_client;//关联另外一个类
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public Client getAddress_client() {
return address_client;
}
public void setAddress_client(Client address_client) {
this.address_client = address_client;
}
}
Client.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="com.hust.javabeans.Client" table="client">
<id name="id" column="ID" type="integer">
<generator class="identity"></generator>
</id>
<property name="clientname" column="CLIENTNAME" type="string"></property>
<property name="phone" column="PHONE" type="string"></property>
<property name="email" column="EMAIL" type="string"></property>
<!-- 映射Client和Address的一对一外键关联,唯一多对一,实际上时一对一关系,这里的name是Client的属性,column是client表的外键-->
<many-to-one name="client_address" class="com.hust.javabeans.Address" column="CLIENTADDRESSID" cascade="all" lazy="false" unique="true"></many-to-one>
</class>
</hibernate-mapping>
<many-to-one unique="true"> 标签在这里表示一对一,many-to-one应该写在有外键的那个表对应的映射文件中
<?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="com.hust.javabeans.Address" table="address">
<id column="ID" name="id" type="integer">
<generator class="identity"/>
</id>
<property name="province" column="PROVINCE" type="string"/>
<property name="city" column="CITY" type="string"/>
<property name="street" column="STREET" type="string"/>
<property name="zipcode" column="ZIPCODE" type="string"/>
<!-- 映射Client和Address的一对一外键关联,name是Address的属性,property-ref是Client中的属性<span style="font-family:Arial, Helvetica, sans-serif;">client_address--></span>
<one-to-one name="address_client" class="com.hust.javabeans.Client" property-ref="client_address"/>
</class>
</hibernate-mapping>
package com.hust.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hust.javabeans.Client;
import com.hust.javabeans.Company;
import SessionFactory.HibernateSessionFactory;
public class OneOneDao {
//添加会员 的方法,只操作主控方
public void addCompany(Company company){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
try{
ts=session.beginTransaction();
System.out.println("oneonedao的addCompany方法执行,执行的sql:");
session.save(company);
System.out.println("oneonedao的addCompany方法完成");
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("[系统错误]oneonedao的addCompany方法中出错");
ex.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
}
//获取会员信息
public Company loadCompany(Integer id){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
Company company=null;
try{
ts=session.beginTransaction();
System.out.println("oneonedao的loadCompany方法执行,执行的sql:");
company=(Company)session.get(Company.class, id);
System.out.println("oneonedao的loadCompany方法完成");
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("[系统错误]早oneonedao的loadCompany方法中出错");
ex.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
return company;
}
//添加客户信息,<span style="font-family: Arial, Helvetica, sans-serif;">只操作主控方</span>
public void addClient(Client client){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
try{
ts=session.beginTransaction();
System.out.println("oneonedao的addclient方法执行,执行的sql:");
session.save(client);
System.out.println("oneonedao的addclient方法完成");
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("[系统错误]oneonedao的addClient方法中出错");
ex.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
}
//获取客户信息
public Client loadClient(Integer id){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
Client client=null;
try{
ts=session.beginTransaction();
System.out.println("oneonedao的loadclient方法执行,执行的sql:");
client=(Client)session.get(Client.class, id);
System.out.println("oneonedao的loadclient方法完成");
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("[系统错误]oneonedao的loadclient方法中出错");
ex.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
return client;
}
}
TestBean.java
package com.hust.test;
import com.hust.dao.OneOneDao;
import com.hust.javabeans.Address;
import com.hust.javabeans.Client;
import com.hust.javabeans.Company;
import com.hust.javabeans.Login;
public class TestBean {
OneOneDao oneonedao=new OneOneDao();
//获取会员信息
public void addCompany(){
Company company=new Company();
Login login=new Login();
login.setLoginname("tuke");
login.setLoginpwd("123456");
company.setCompanyname("呵呵哒的微笑");
company.setLinkman("张珊");
company.setTelephone("010-12345678");
company.setEmail("beijing@163.com");
//PO对象之间互相设置关联关系
login.setCompany(company);
company.setLogin(login);
System.out.println("testbean的addcompany方法执行开始");
//添加会员信息,保存到数据库,company保存到数据库,同时login也保存到数据库,只操作主控方
oneonedao.addCompany(company);
System.out.println("testbean的addcompany方法执行完成");
}
//获取会员信息
public Company loadCompany(Integer id){
//从数据库获得company的同时也获得了login表的记录
System.out.println("testbean的loadcompany方法执行开始");
return oneonedao.loadCompany(id);
}
//添加客户信息
public void addClient(){
Client client=new Client();
Address address=new Address();
address.setProvince("湖北省");
address.setCity("武汉市");
address.setStreet("临江大道");
address.setZipcode("100083");
client.setClientname("李想");
client.setPhone("027-76866876");
client.setEmail("lixiang@126.com");
//PO对象之间互相设置关联关系
address.setAddress_client(client);
client.setClient_address(address);
System.out.println("testbean的addclient方法执行开始");
//添加客户信息,保存到数据库,client保存到数据库,同时address也保存到数据库,只操作主控方
oneonedao.addClient(client);
System.out.println("testbean的addclient方法执行完成");
}
//获得客户信息
public Client loadClient(Integer id){
System.out.println("testbean的loadclient方法执行开始");
return oneonedao.loadClient(id);
}
}
结果显示为:
控制台打印的sql是:
testbean的addcompany方法执行开始
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
oneonedao的addCompany方法执行,执行的sql:
Hibernate:
insert
into
company
(COMPANYNAME, LINKMAN, TELEPHONE, EMAIL)
values
(?, ?, ?, ?)
oneonedao的addCompany方法完成
Hibernate:
insert
into
login
(LOGINNAME, LOGINPWD, ID)
values
(?, ?, ?)
testbean的addcompany方法执行完成 //主键关联时,两个insert语句不是连续完成的
testbean的addclient方法执行开始
oneonedao的addclient方法执行,执行的sql:
Hibernate:
insert
into
address
(PROVINCE, CITY, STREET, ZIPCODE)
values
(?, ?, ?, ?)
Hibernate:
insert
into
client
(CLIENTNAME, PHONE, EMAIL, CLIENTADDRESSID)
values
(?, ?, ?, ?)
oneonedao的addclient方法完成
testbean的addclient方法执行完成 //外键关联时,连续执行两个insert语句
testbean的loadcompany方法执行开始
oneonedao的loadCompany方法执行,执行的sql:
Hibernate:
select
company0_.ID as ID2_1_,
company0_.COMPANYNAME as COMPANYN2_2_1_,
company0_.LINKMAN as LINKMAN2_1_,
company0_.TELEPHONE as TELEPHONE2_1_,
company0_.EMAIL as EMAIL2_1_,
login1_.ID as ID3_0_,
login1_.LOGINNAME as LOGINNAME3_0_,
login1_.LOGINPWD as LOGINPWD3_0_
from
company company0_
left outer join
login login1_
on company0_.ID=login1_.ID
where
company0_.ID=?
oneonedao的loadCompany方法完成
testbean的loadclient方法执行开始
oneonedao的loadclient方法执行,执行的sql:
Hibernate:
select
client0_.ID as ID1_0_,
client0_.CLIENTNAME as CLIENTNAME1_0_,
client0_.PHONE as PHONE1_0_,
client0_.EMAIL as EMAIL1_0_,
client0_.CLIENTADDRESSID as CLIENTAD5_1_0_
from
client client0_
where
client0_.ID=?
Hibernate:
select
address0_.ID as ID0_1_,
address0_.PROVINCE as PROVINCE0_1_,
address0_.CITY as CITY0_1_,
address0_.STREET as STREET0_1_,
address0_.ZIPCODE as ZIPCODE0_1_,
client1_.ID as ID1_0_,
client1_.CLIENTNAME as CLIENTNAME1_0_,
client1_.PHONE as PHONE1_0_,
client1_.EMAIL as EMAIL1_0_,
client1_.CLIENTADDRESSID as CLIENTAD5_1_0_
from
address address0_
left outer join
client client1_
on address0_.ID=client1_.CLIENTADDRESSID
where
address0_.ID=?
Hibernate:
select
client0_.ID as ID1_0_,
client0_.CLIENTNAME as CLIENTNAME1_0_,
client0_.PHONE as PHONE1_0_,
client0_.EMAIL as EMAIL1_0_,
client0_.CLIENTADDRESSID as CLIENTAD5_1_0_
from
client client0_
where
client0_.CLIENTADDRESSID=?
oneonedao的loadclient方法完成