首先说明一下什么叫主键以及外键。
主键和外键是对于数据库来说的,数据库的表才有主键外键的说法。
主键:主键是指标识某个表中唯一且非空的一条记录行的列,这个列中的值不允许有重复的值,用于确定一个表中的一条记录,实际上主键就是告诉别人:这个数据列是唯一的。
外键:引用另外一个表中的主键,在当前表中不一定为唯一的,但是在被引用表中一般唯一。对于关系型数据库来说(比如MySQL)外键是联系数据表之间的唯一方式,主要目的是控制存储在外键表中的数据。
建立外键的前提:本表的列必须与外键类型相同(外键必须是外表主键)。
例如:
表1:用户编号(主键) 用户名称 部门编号(外键)
表2:部门编号(主键) 部门名称
这里来讲:对于表1来说,用户编号是主键,对于表2来讲部门编号是主键,然后表1引用表2的主键作为外键,这样就将两个数据表关联起来了,表一中每个部门编号表二都会有个部门名称相对应。
下面开始映射集合属性:
因为关于Hibernate中映射List、Array、Set、以及Map的方式相差不大,此处仅拿映射List展开,其他稍作介绍。
Hibernate映射List集合
一:PersonList.java
Person类中除了普通属性外,还有一个List集合属性:schools,该属性对应多个学校。
package com.mao; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.persistence.Basic; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.Lob; import javax.persistence.OrderColumn; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @Entity @Table(name="personList_inf") public class PersonList { //分别指定主键、主键列名、主键为自增 @Id @Column(name="person_id",nullable=false) @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; @Column (name="person_name",length=50) private String name; @Lob @Basic(fetch=FetchType.LAZY) private byte[]pic; //通过@Temporal注解 可以完成持久化属性映射到数据库的时间格式 @Temporal(TemporalType.DATE) private Date birth; //如果集合通过泛型指定了类型 则可以不通过targetClass指定类型 @ElementCollection(targetClass=String.class) //指定保存集合的数据表 并指定外键列 @CollectionTable(name="schools_inf",[email protected] (name="person_id",nullable=false)) //指定保存集合元素的列为:school_name @Column (name="school_name") //映射集合元素的索引的列 @OrderColumn(name="list_order") private List<String> school=new ArrayList<>(); //相应的set、get方法 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public byte[] getPic() { return pic; } public void setPic(byte[] pic) { this.pic = pic; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public List<String> getSchool() { return school; } public void setSchool(List<String> school) { this.school = school; } }
二:主程序 PersonManagerList.java
package com.mao; import java.io.File; import java.io.FileInputStream; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; public class PersonManagerList { public static void main(String[]args) throws Exception{ Configuration cof=new Configuration().configure(); ServiceRegistryBuilder serviceRegistryBuilder=new ServiceRegistryBuilder().applySettings(cof.getProperties()); ServiceRegistry registry=serviceRegistryBuilder.buildServiceRegistry(); SessionFactory sf=cof.buildSessionFactory(registry); Session sess=sf.openSession(); Transaction tx=sess.beginTransaction(); PersonList person=new PersonList(); person.setName("VipMao"); //创建文件 上传图片到数据库 File file=new File("image/2.jpg"); byte[]content=new byte[(int) file.length()]; //创建读取数据流来读取图片对象file并存入字节数组content new FileInputStream(file).read(content); person.setPic(content); person.setBirth(new Date()); person.getSchool().add("菜鸟学院"); //保存信息并将对象持久化 sess.save(person); //提交事务 tx.commit(); sess.close(); sf.close(); } }
三:配置文件 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-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.characterEncoding">utf-8</property> <!-- 指定连接池最大连接数 --> <property name="hibernate.c3p0.max_size">20</property> <!-- 指定连接池最小连接数 --> <property name="hibernate.c3p0.min_size">1</property> <!-- 指定连接池里连接超时时长 --> <property name="hibernate.c3p0.timeout">5000</property> <!-- 指定连接池里做大缓存多少个Statement对象 --> <property name="hibernate.c3p0.max_statements">50</property> <!-- 是否根据需要自动建表 --> <property name="hbm2ddl.auto">update</property> <!-- 是否显示sql语句 --> <property name="show_sql">true</property> <!-- 将SQL脚本进行格式化后再输出 --> <property name="hibernate.format_sql">true</property> <!-- 设置连接数据库所使用的方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 罗列所有持久化类名 --> <!-- <mapping class="com.mao.Person"/> <mapping class="com.mao.PersonMap"/> <mapping class="com.mao.PersonArray"/> <mapping class="com.mao.PersonSet"/> --> <mapping class="com.mao.PersonList"/> </session-factory> </hibernate-configuration>
四:运行结果
从控制台输出的SQL语句可以看出,先在personList_inf表中插入了普通属性,然后通过外键列在schools_inf表中插入集合信息,下面数据库结果:
这样person_id是表一的主键 ,person_id也为表二的主键,然后表一把表二的主键作为外键,这样就将两个表建立起联系了,每在表一添加一个person_id的时候表二都会对应一个school_name和list_order(集合索引)。
五:映射集合常用的注解
@ElementCollection:用于映射集合属性
@CollectionTable:用于映射集合属性表,name属性指定存储集合属性表的表名,joinColumns属性映射外键列
@Column:用于映射保存集合元素的数据列
@OrderColumn:用于映射集合的索引列,像Set这种无序集合可以不用此注解
Hibernate映射Array集合
一:PersonArray.java(只给出集合部分变动)
@ElementCollection(targetClass=String.class) @CollectionTable(name="arraySchool_inf" ,[email protected](name="id",nullable=false)) //指定保存集合元素的列为school_name @Column(name="school_name") //映射集合元素的索引 @OrderColumn(name="array_order") private String[]school;
二:PersonManagerArray.java
PersonArray person=new PersonArray(); person.setName("VipMao"); File file=new File("image/2.jpg"); byte[]content=new byte[(int) file.length()]; //创建读取数据流来读取图片对象file并存入字节数组content new FileInputStream(file).read(content); person.setPic(content); person.setBirth(new Date()); System.out.println("日期为:"+new Date()); String[]school=new String[3]; school[0]="菜鸟学院"; school[1]="小牛学院"; school[2]="大牛学院"; person.setSchool(school); sess.save(person);
三:运行结果
Hibernate映射Set集合
一:PersonSet.java
@ElementCollection @CollectionTable(name="schoolSet_inf" , [email protected](name="person_id",nullable=false)) @Column(name="school_name",nullable=false) private Set<String>schools=new HashSet<>();
二:PersonManagerSet.java
PersonSet person=new PersonSet(); person.setName("VipMao"); person.setAge("24"); person.getSchools().add("菜鸟学院"); person.getSchools().add("小牛学院"); person.getSchools().add("大牛学院"); sess.save(person);
三:运行结果:
可以看出,因为Set集合的无序性,我们并没有通过@OrderColumn映射集合的索引列。
Hibernate映射Map集合
一:PersonMap.java
@ElementCollection(targetClass=Float.class) @CollectionTable(name="score_inf",[email protected](name="person_id",nullable=false)) //映射保存Map key的数据列 @MapKeyColumn(name="subject_name") //指定Map key的类型为String类型 @MapKeyClass(String.class) //映射保存 Map value的数据列 @Column(name="mark") private Map<String,Float>scores=new HashMap<>();
二:PersonManagerMap.java
PersonMap person = new PersonMap(); person.setAge("24"); person.setName("VipMao"); // 向person的Map集合属性中添加key-value对 person.getScores().put("语文" , 90f); person.getScores().put("英文" , 99f); session.save(person);
三:运行结果
最后说一下各集合的联合主键问题:
List联合主键:持久化外键列+集合元素索引列
Set联合主键:持久化外键列+Set元素列(元素列不能为空)
Map联合主键:持久化外键列+集合Key列