双向一对一
例:
数据库表:
Users表中有字段:uid,uname,cardid
Cards表中有字段:cid,cnumber
EntityBean Users和Cards
类:
Users
属性:Integer id,String name,Cards cards
每个属性修饰get()方法
其中cards的get()方法修饰:
@OneToOne(cascade=CascadeType.ALL,optional=true)
@JoinColumn(name="cardid",referencedColumnName="cid",unique=true)
public Cards getCards() {
return cards;
}
cascade:级联,CascadeType有ALL,MERGE,REFRESH,PERSIST,REMOVE
optional:是否允许为空,true――允许,false――不允许
name="cardid":Users表中做外键的列
cid:Cards表中的主键
referencedColumnName="cid":唯一
Cards
属性:integer id,String number,Users users
每个属性修饰get()方法
其中users的get()方法修饰:
@OneToOne(mappedBy="cards",cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=true)
public Users getUser() {
return user;
}
mappedBy="cards":cards为Users中的属性,此设置为以Cards的对方Users维护关系
fetch=FetchType.LAZY:延时加载
FetchType有MERGE,LAZY
操作EntityBean时双方都New出来并双方都set对方
方法:有外键的一方先配
一对多
多方:
@ManyToOne(cascade=...)
@JoinColumn(name="",refrencedColumnName="")
一方:
@OneToMany(mappedBy="",cascade...fetch)
多对多
一方:
@ManyToMany(mappedBy)
另一方:
@ManyToMany(cascade...fetch..)
@JoinTable(name="中间表", ="中间表中对应的列",refrencedColumnName="本表主键")}, ="中间表对方对应的列",refrencedColumnName="主键")})
**********
1、在JBoss中配置数据源
方法见四、EJB实体Bean开发
并且保证JBoss中有该数据库连接jar包,例如:
2、建立项目
3、在persitence.xml中配置数据源连接
配置完成后会在EJB端项目中创建一个META-INF/persitence.xml文件,在该文件中进行连接等配置
(1)配置数据源
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="mysql" transaction-type="JTA">
<jta-data-source>java:jdbc/mysql</jta-data-source>
</persistence-unit>
</persistence>
(2)打开show_sql
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="mysql" transaction-type="JTA">
<jta-data-source>java:jdbc/mysql</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
4、生成EntityBean映射
DROP TABLE person ;
DROP TABLE groups ;
CREATE TABLE groups (
id int primary key auto_increment ,
title varchar(20) not null ,
description text not null
);
CREATE TABLE person (
uid varchar(18) primary key ,
name varchar(20) not null,
age int not null,
gid int not null,
foreign key (gid) references groups (id) on delete cascade
);
package org.mldn.lin.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "person", catalog = "testdb", uniqueConstraints = {})
public class Person implements java.io.Serializable {
private String uid;
private Groups groups;
private String name;
private Integer age;
public Person() {
}
public Person(String uid, Groups groups, String name, Integer age) {
this.uid = uid;
this.groups = groups;
this.name = name;
this.age = age;
}
@Id
@Column(name = "uid", unique = true, nullable = false, insertable = true, updatable = true, length = 18)
public String getUid() {
return this.uid;
}
public void setUid(String uid) {
this.uid = uid;
}
// 表示该类与Groups类有多对一关系
// cascade表示级联关系,是否同时进行操作,与hibernate中的cascade相同,如果不写任何内容表示none值,如果填写可以从CascadeType的enum中选择适合的方式
// fetch表示加载方式,如果值为LAZY表示使用延迟加载,如果为EAGER表示不使用
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
// 表示关系字段的映射配置
@JoinColumn(name = "gid", unique = false, nullable = false, insertable = true, updatable = true)
public Groups getGroups() {
return this.groups;
}
public void setGroups(Groups groups) {
this.groups = groups;
}
@Column(name = "name", unique = false, nullable = false, insertable = true, updatable = true, length = 20)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "age", unique = false, nullable = false, insertable = true, updatable = true)
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
package org.mldn.lin.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "groups", catalog = "testdb", uniqueConstraints = {})
public class Groups implements java.io.Serializable {
private Integer id;
private String title;
private String description;
private Set<Person> persons = new HashSet<Person>(0);
public Groups() {
}
public Groups(Integer id, String title, String description) {
this.id = id;
this.title = title;
this.description = description;
}
public Groups(Integer id, String title, String description,
Set<Person> persons) {
this.id = id;
this.title = title;
this.description = description;
this.persons = persons;
}
@Id
//自增长
@GeneratedValue
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "title", unique = false, nullable = false, insertable = true, updatable = true, length = 20)
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
@Column(name = "description", unique = false, nullable = false, insertable = true, updatable = true, length = 65535)
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
//表示该类与Person包含一对多关系,在对方对象中也包含一个对应的属性叫groups
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, mappedBy = "groups")
public Set<Person> getPersons() {
return this.persons;
}
public void setPersons(Set<Person> persons) {
this.persons = persons;
}
5、新建SessionBean操作EntityBean
srcànewàEJB3 SessionBean
package org.mldn.lin.session;
import javax.ejb.Remote;
import org.mldn.lin.entity.Person;
@Remote
public interface PersonDAORemote {
public boolean doCreate(Person person)throws Exception;
public Person findById(String uid)throws Exception;
package org.mldn.lin.session;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.mldn.lin.entity.Person;
@Stateless
public class PersonDAO implements PersonDAORemote {
@PersistenceContext
private EntityManager em;
public boolean doCreate(Person person) throws Exception {
// TODO Auto-generated method stub
this.em.persist(person);
return true;
}
public Person findById(String uid) throws Exception {
// TODO Auto-generated method stub
Person person=this.em.find(Person.class, uid);
return person;
}
package org.mldn.lin.session;
import javax.ejb.Remote;
import org.mldn.lin.entity.Groups;
@Remote
public interface GroupsDAORemote {
public boolean doCreate(Groups groups)throws Exception;
public Groups findById(int gid)throws Exception;
package org.mldn.lin.session;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.mldn.lin.entity.Groups;
@Stateless
public class GroupsDAO implements GroupsDAORemote {
@PersistenceContext
private EntityManager em;
public boolean doCreate(Groups groups) throws Exception {
// TODO Auto-generated method stub
this.em.persist(groups);
return true;
}
public Groups findById(int gid) throws Exception {
// TODO Auto-generated method stub
Groups groups=this.em.find(Groups.class, gid);
return groups;
}
6、EJB端项目发布
7、在Web端建立测试类测试
通过测试类进行测试,需要将 拷贝到lib下即可
package org.mldn.lin.test;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.mldn.lin.entity.Groups;
import org.mldn.lin.session.GroupsDAORemote;
import org.mldn.lin.session.PersonDAORemote;
public class Test {
public static void main(String[] args) {
// 定义查找参数,通过定义这些参数找到该公共空间
Properties pro = new Properties();
pro.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
pro.setProperty("java.naming.provider.url", "192.168.1.187:1099");
pro.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
// 通过JNDI查找发布的接口
try {
Context ctx = new InitialContext(pro);
// 开始查找接口
GroupsDAORemote gdao=(GroupsDAORemote) ctx.lookup("GroupsDAO/remote");
Groups groups=new Groups();
groups.setTitle("111");
// 打印结果
System.out.println(gdao.doCreate(groups));
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
8、处理jar包
此处采用测试类测试,而且因为有映射关系,所以会出现缺少支持类的错误,因此这里需要将用到的Hibernate3支持包拷贝到web端的lib下
对应的再查找所有需要用到的支持包,都包含以下内容:
, ,
在JBoss的D:\jboss-4.2.0.GA\server\default\lib目录下可以找到这些jar包,如果对于映射关系还不满足,那么可以在原来的SSH项目中找到完整版的Hibernate3的支持jar包来代替
9、处理Lazy
package org.mldn.lin.test;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.mldn.lin.entity.Groups;
import org.mldn.lin.entity.Person;
import org.mldn.lin.session.GroupsDAORemote;
import org.mldn.lin.session.PersonDAORemote;
public class Test {
public static void main(String[] args) {
// 定义查找参数,通过定义这些参数找到该公共空间
Properties pro = new Properties();
pro.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
pro.setProperty("java.naming.provider.url", "192.168.1.187:1099");
pro.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
// 通过JNDI查找发布的接口
try {
Context ctx = new InitialContext(pro);
// 开始查找接口
GroupsDAORemote gdao=(GroupsDAORemote) ctx.lookup("GroupsDAO/remote");
PersonDAORemote pdao=(PersonDAORemote) ctx.lookup("PersonDAO/remote");
Groups groups=new Groups();
groups.setTitle("111");
groups.setDescription("第一组");
Person person=new Person();
person.setUid("lin");
person.setName("mldn");
person.setAge(25);
Groups g=new Groups();
g.setId(1);
person.setGroups(g);
Person person1=new Person();
person1.setUid("wei");
person1.setName("mldn");
person1.setAge(25);
person1.setGroups(g);
// 打印结果
// System.out.println(gdao.doCreate(groups));
// System.out.println(gdao.findById(1).getTitle());
// System.out.println(pdao.doCreate(person));
// System.out.println(pdao.doCreate(person1));
// System.out.println(pdao.findById("lin"));
System.out.println(pdao.findById("lin").getGroups().getTitle());
//System.out.println(gdao.findById(1).getPersons().size());
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
当进行级联查询时,不管通过一查多,还是通过多的查一,都会报lazy
严重: could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
解决方案:
可以将LAZY关闭或在实现类中使用.的方式先进行查询
package org.mldn.lin.session;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.mldn.lin.entity.Groups;
@Stateless
public class GroupsDAO implements GroupsDAORemote {
@PersistenceContext
private EntityManager em;
public boolean doCreate(Groups groups) throws Exception {
// TODO Auto-generated method stub
this.em.persist(groups);
return true;
}
public Groups findById(int gid) throws Exception {
// TODO Auto-generated method stub
Groups groups=this.em.find(Groups.class, gid);
groups.getPersons().size();
return groups;
}
package org.mldn.lin.session;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.mldn.lin.entity.Person;
@Stateless
public class PersonDAO implements PersonDAORemote {
@PersistenceContext
private EntityManager em;
public boolean doCreate(Person person) throws Exception {
// TODO Auto-generated method stub
this.em.persist(person);
return true;
}
public Person findById(String uid) throws Exception {
// TODO Auto-generated method stub
Person person=this.em.find(Person.class, uid);
person.getGroups().getTitle();
return person;
}
**********
定义多对一关联映射
Company与Employee
多的一端定义的注解和平常的一样
public class Company { @Id
@GeneratedValue
private int id;
private String name;但是在一的一端需要定义@ManyToOne注解
@Entity
public class Employee { @Id
@GeneratedValue
private int id;
private String name;
@ManyToOne
@JoinColumn(name="CID")
private Company company;这里的多对一应该这样理解:多个Employee对应一个Company,通过在Employee上增加外键指向Company @JoinColumn(name="CID")的意思是在Employee这张表中加入CID字段,与Company的主键关联,通过Employee就能查询到他所对应的Company定义一对一关联映射
Customer与CustomerNo@Entity
public class Customer {
@Id
@GeneratedValue
private int id;
private String name;
@OneToOne
@PrimaryKeyJoinColumn //主键关联映射
private CustomerNo customerno;@PrimaryKeyJoinColumn 注解的含义是:通过主键关联映射,也就是Customer和CustomerNo的主键是一样的若要定义双向关联映射,需要在CustomerNo也加入@OneToOne@Entity
public class CustomerNo {
@Id
@GeneratedValue
private int id;
private String name;
@OneToOne(mappedBy="customerno")
private Customer customer;mappedBy="customerno"的含义,只需要在Customer一端定义映射的规则,CustomerNo一端使用另外一端的映射规则
*******
1.映射的表名或列名与数据库保留字同名时的处理
如果应用采用的数据库是Mysql,当映射的表名或列名与数据库保留字同名时,持久化引掣转绎后的SQL在执行时将会出错。
@Table(name = "`Order`")
如果数据库是Sqlserver 可以用 [] 把表名或列名括起来。Sqlserver 不加[]也能执行成功,建议在出错的情况下使用。
该方法针对具体数据库,不利于数据库移植。建议大家在不得已的情况下使用。
2.一对多及多对一映射
@OneToMany(mappedBy="order",cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OrderBy(value = "id ASC")
来源:(http://blog.sina.com.cn/s/blog_4ae1bd8f010009n0.html) - EJB--关系/对象映射_buffet_新浪博客
下面是@OneToMany注释的属性介绍:
2.1>targetEntity
Class类型的属性。
定义关系类的类型,默认是该成员属性对应的类类型,所以通常不需要提供定义。
2.2>mappedBy
String类型的属性。
定义类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题。
2.3>cascade
CascadeType[]类型。
该属性定义类和类之间的级联关系。定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。举个例子:Order 和OrderItem有级联关系,那么删除Order 时将同时删除它所对应的OrderItem对象。而如果OrderItem还和其他的对象之间有级联关系,那么这样的操作会一直递归执行下去。cascade的值只能从CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)中选择一个或多个。还有一个选择是使用CascadeType.ALL,表示选择全部四项。
2.4>fetch
FetchType类型的属性。
可选择项包括:FetchType.EAGER和FetchType.LAZY。前者表示关系类(本例是OrderItem类)在主类(本例是Order类)加载的时候同时加载,后者表示关系类在被访问时才加载。默认值是FetchType. LAZY。
@ManyToOne注释有四个属性:targetEntity、cascade、fetch和optional,前三个属性的具体含义和@OneToMany注释的同名属性相同,
但@ManyToOne注释的fetch属性默认值是FetchType.EAGER。
optional属性是定义该关联类对是否必须存在,值为false时,关联类双方都必须
存在,如果关系被维护端不存在,查询的结果为null。值为true时, 关系被维护端可以不存在,查询的结果仍然会返回关系维护端,在关系维护端中指向关系被维护端的属性为null。optional属性的默认值是true。举个例:某项订单(Order)中没有订单项(OrderItem),如果optional属性设置为false,获取该项订单(Order)时,得到的结果为null,如果optional属性设置为true,仍然可以获取该项订单,但订单中指向订单项的属性为null。实际上在解释Order 与OrderItem的关系成SQL时,optional属性指定了他们的联接关系optional=false联接关系为inner join, optional=true联接关系为left join。
@JoinColumn(name = "order_id")注释指定OrderItem映射表的order_id列作为外
键与Order 映射表的主键列关联。
当业务方法需要把一个实体Bean作为参数返回给客户端时,除了实体Bean本身需要
实现Serializable接口之外,如果关联类(OrderItem)是延迟加载,还需在返回实
体Bean之前通过访问关联类的方式加载关联类。否则在客户端访问关联类时将会抛
出加载例外。
public Order getOrderByID(Integer orderid) {
Order order = em.find(Order.class, orderid);
order.getOrderItems().size();
//因为是延迟加载,通过执行size()这种方式获取订单下的所有订单项
return order;
}
另外不管是否延迟加载,通过join fetch关联语句都可显式加载关联类,如业务方法getAllOrder 。
public List getAllOrder() {
Query query = em.createQuery("select o from Order o inner join fetch o.orderItems order by
o.orderid");
List result = query.getResultList();
return result;
}
3.一对一映射
@OneToOne注释五个属性:targetEntity、cascade、fetch、optional和mappedBy, 前四个属性的具体含义与@ManyToOne注释的同名属性一一对应,请大家参考前面章节中的内容,fetch属性默认值是FetchType.EAGER。mappedBy属性的具体含义与@OneToMany注释的同名属性相同。上面的optional = true设置idcard属性可以为null,也就是允讦没有身份证,未成年人就是没有身份证的。
public Person getPersonByID(Integer personid) {
Person person = em.find(Person.class, personid);
return person;
}
4.多对多映射
public Teacher getTeacherByID(Integer teacherid) {
Teacher teacher= em.find(Teacher.class, teacherid);
if (teacher!=null) teacher.getStudents().size();
return teacher;
}
**********
1,一对一关联映射
1)主键关联
@Entity
public class Customer {
@Id
private int id;
private String name;
@OneToOne
@PrimaryKeyJoinColumn
private CustomerNo customerNo;
@Entity
public class CustomerNo {
@Id
private int id;
private String sn;
@OneToOne(mappedBy="customerNo")
private Customer customer;
2)唯一外键关联
@Entity
public class Customer1 {
@Id
private int id;
private String name;
@OneToOne
@JoinColumn(name="customer1NoId",unique=true)
private Customer1No customer1No;
@Entity
public class Customer1No {
@Id
private int id;
private String sn;
@OneToOne(mappedBy="customer1No")
private Customer1 customer1;
2,一对多
1)一对多单向
@Entity
public class Classes {
@Id
private int id;
private String cname;
@OneToMany
private Set<Student> students;
@Entity
public class Student {
@Id
private int id;
private String name;
2)一对多双向
@Entity
public class Classes1 {
@Id
private int id;
private String cname;
@OneToMany(mappedBy="classes1")
private Set<Student1> student1s;
@Entity
public class Student1 {
@Id
private int id;
private String name;
@ManyToOne
private Classes1 classes1;
*********