JAP映射关联关系

    xiaoxiao2021-03-25  76

    JAP映射关联关系

    1. 单向多对一

    Order(多)–>Customer(一)

    关键点:

    Order里有一个Customer的成员

    /** *@JoinColumn:来映射外键 *@ManyToOne:映射多对一的关系 */ @JoinColumn(name="customer_id") @ManyToOne(fetch=FetchType.LAZY)//使用懒加载 public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; }

    1. Order.java:

    package com.bart.jpa.beans; import javax.persistence.Column; 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.ManyToOne; import javax.persistence.Table; @Table(name="jpa_order") @Entity public class Order { @Override public String toString() { return "Order [id=" + id + ", name=" + name + ", customer=" +customer + "]"; } @Column(length=10,nullable=false) @GeneratedValue(strategy=GenerationType.AUTO) @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="o_name",length=20,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } /** *@JoinColumn:来映射外键 *@ManyToOne:映射多对一的关系 */ @JoinColumn(name="customer_id") @ManyToOne(fetch=FetchType.LAZY)//使用懒加载 public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } private Integer id; private String name; private Customer customer; public Order(String name, Customer customer) { super(); this.name = name; this.customer = customer; } public Order(String name) { super(); this.name = name; } public Order() { super(); } }

    2. Customer.java

    package com.bart.jpa.beans; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; /** * 使用JPA的注解创建对应的数据表 * @author hp * */ @Cacheable(true) @Table(name="JPA_CUSTOMER") @Entity public class Customer { @Override public String toString() { return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + ", createTime=" + createTime + ", birth=" + birth + "]"; } private Integer id; private String lastName; private String email; private Integer age; private Date createTime; private Date birth; //private Set<Order> orders= new HashSet<Order>(); public Customer(String lastName, String email, Integer age, Date createTime) { super(); this.lastName = lastName; this.email = email; this.age = age; this.createTime = createTime; } public Customer() { super(); } @GeneratedValue(strategy=GenerationType.AUTO)//主键自动生成 @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="last_name",length=20,nullable=false) public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Column(length=30) public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Column(length=3) public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Temporal(TemporalType.DATE)//显示格式(yyyy-MM-dd) public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } @Temporal(TemporalType.TIMESTAMP) public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Transient//工具方法,表示不需要映射为数据表的一个列 public String getInfo(){ return "lastName:"+lastName+",email:"+email; } }

    3. Junit测试

    把EntityManagerFactory,EntityManager,EntityTransaction的创建和销毁分别放在@before和@after中执行

    private String persistenceUnitName = "jpa-1"; private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName); private EntityManager manager = entityManagerFactory.createEntityManager(); private EntityTransaction transaction ; @Before public void before(){ //1.创建EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName); //2.创建EntityManager manager = entityManagerFactory.createEntityManager(); //3.开启事务管理 transaction = manager.getTransaction(); transaction.begin(); } @After public void after(){ transaction.commit(); //6. 关闭factory entityManagerFactory.close(); //7. 关闭manager manager.close(); }

    3.1 测试插入数据

    /** * 添加的时候应该添加 1 的一方,在添加 n 的一方 * 减少数据库的操作 */ @Test public void testManyToOnePersist(){ Customer customer = new Customer(); customer.setLastName("GG"); customer.setEmail("GG@qq.cpm"); customer.setCreateTime(new Date()); Order order1 = new Order("O-AA",customer); Order order2 = new Order("O-BB",customer); manager.persist(customer); manager.persist(order1); manager.persist(order2); }

    输出SQL语句:

    Hibernate: insert into JPA_CUSTOMER (age, birth, createTime, email, last_name) values (?, ?, ?, ?, ?) Hibernate: insert into jpa_order (customer_id, o_name) values (?, ?) Hibernate: insert into jpa_order (customer_id, o_name) values (?, ?)

    此时MySQL数据库中会创建两张表:

    jpa_customer mysql> select * from jpa_customer; +----+------+-------+---------------------+-----------+-----------+ | id | age | birth | createTime | email | last_name | +----+------+-------+---------------------+-----------+-----------+ | 1 | NULL | NULL | 2017-03-12 19:11:47 | GG@qq.cpm | GG | +----+------+-------+---------------------+-----------+-----------+ 1 row in set jpa_order mysql> select * from jpa_order; +----+--------+-------------+ | id | o_name | customer_id | +----+--------+-------------+ | 1 | O-AA | 1 | +----+--------+-------------+ | 2 | O-BB | 1 | +----+--------+-------------+ 1 row in set

    3.2 测试读取数据:

    //使用普通加载方式的话就是执行了左外查询 //使用fetch的lazy加载的话就是查询两次 @Test public void testManyToOneFind(){ Order order = manager.find(Order.class, 1); System.out.println(order.getName()); System.out.println(order.getCustomer().getLastName()); }

    输出SQL语句:

    Hibernate: select order0_.id as id1_6_0_, order0_.customer_id as customer3_6_0_, order0_.o_name as o_name2_6_0_ from jpa_order order0_ where order0_.id=? O-AA Hibernate: select customer0_.id as id1_0_0_, customer0_.age as age2_0_0_, customer0_.birth as birth3_0_0_, customer0_.createTime as createTi4_0_0_, customer0_.email as email5_0_0_, customer0_.last_name as last_nam6_0_0_ from JPA_CUSTOMER customer0_ where customer0_.id=? GG

    3.3 测试删除数据

    /** * 删除的时候应该先删除 n 的一方再删除 1 的一方 */ @Test public void testManyToOneRemove(){ Order order = manager.find(Order.class, 7); manager.remove(order); }

    数据库:

    mysql> select * from jpa_order; +----+--------+-------------+ | id | o_name | customer_id | +----+--------+-------------+ | 2 | O-BB | 1 | +----+--------+-------------+ 1 row in set

    3.4测试更新数据

    @Test public void testManyToOneUpdate(){ Order order = manager.find(Order.class, 2); order.getCustomer().setLastName("GGG"); }

    输出:

    Hibernate: select order0_.id as id1_6_0_, order0_.customer_id as customer3_6_0_, order0_.o_name as o_name2_6_0_ from jpa_order order0_ where order0_.id=? Hibernate: select customer0_.id as id1_0_0_, customer0_.age as age2_0_0_, customer0_.birth as birth3_0_0_, customer0_.createTime as createTi4_0_0_, customer0_.email as email5_0_0_, customer0_.last_name as last_nam6_0_0_ from JPA_CUSTOMER customer0_ where customer0_.id=? Hibernate: update JPA_CUSTOMER set age=?, birth=?, createTime=?, email=?, last_name=? where id=? mysql> select * from jpa_customer; +----+------+-------+---------------------+-----------+-----------+ | id | age | birth | createTime | email | last_name | +----+------+-------+---------------------+-----------+-----------+ | 1 | NULL | NULL | 2017-03-12 19:11:47 | GG@qq.cpm | GGG | +----+------+-------+---------------------+-----------+-----------+ 1 row in set

    2. 单向一对多&&双向多对一

    为什么这两个能放在一块呢? 因为一对多和多对一在单向的时候是相对的例如表A和表B,当A作为1时,B为n时,在A的角度就是单向一对多(1–>n),反过来就是单向多对一(n–>1)

    所以直接看双向多对一 此时Order作为多的多方(n),Customer作为一方(1) 还是以上面两个为表格为例子

    关键点

    多方:

    //使用 @OneToMany 来映射 1-n 的关联关系 //使用 @JoinColumn 来映射外键列的名称 //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略 //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. /** 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性,表示由多方维护与关联关系 * 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. */ // @JoinColumn(name="customer_id") @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer") public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; }

    一方:

    // /** // *@JoinColumn:来映射外键 // *@ManyToOne:映射多对一的关系 // */ @JoinColumn(name="customer_id") @ManyToOne(fetch=FetchType.LAZY)//使用懒加载 public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; }

    Customer.java

    package com.bart.jpa.beans; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.Column; 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.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; /** * 使用JPA的注解创建对应的数据表 * @author hp * */ @Cacheable(true) @Table(name="JPA_CUSTOMER") @Entity public class Customer { //使用 @OneToMany 来映射 1-n 的关联关系 //使用 @JoinColumn 来映射外键列的名称 //可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略 //可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略. /** 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性,表示由多方维护与关联关系 * 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. */ // @JoinColumn(name="customer_id") @OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer") public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } @Override public String toString() { return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + ", createTime=" + createTime + ", birth=" + birth + "]"; } private Integer id; private String lastName; private String email; private Integer age; private Date createTime; private Date birth; private Set<Order> orders= new HashSet<Order>(); public Customer(String lastName, String email, Integer age, Date createTime) { super(); this.lastName = lastName; this.email = email; this.age = age; this.createTime = createTime; } public Customer() { super(); } @GeneratedValue(strategy=GenerationType.AUTO)//主键自动生成 @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="last_name",length=20,nullable=false) public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Column(length=30) public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Column(length=3) public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Temporal(TemporalType.DATE)//显示格式(yyyy-MM-dd) public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } @Temporal(TemporalType.TIMESTAMP) public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Transient//工具方法,表示不需要映射为数据表的一个列 public String getInfo(){ return "lastName:"+lastName+",email:"+email; } }

    Order.java

    package com.bart.jpa.beans; import javax.persistence.Column; 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.ManyToOne; import javax.persistence.Table; @Table(name="jpa_order") @Entity public class Order { @Override public String toString() { return "Order [id=" + id + ", name=" + name + ", customer=" +customer + "]"; } @Column(length=10,nullable=false) @GeneratedValue(strategy=GenerationType.AUTO) @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="o_name",length=20,nullable=false) public String getName() { return name; } public void setName(String name) { this.name = name; } // /** // *@JoinColumn:来映射外键 // *@ManyToOne:映射多对一的关系 // */ @JoinColumn(name="customer_id") @ManyToOne(fetch=FetchType.LAZY)//使用懒加载 public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } private Integer id; private String name; private Customer customer; public Order(String name, Customer customer) { super(); this.name = name; this.customer = customer; } public Order(String name) { super(); this.name = name; } public Order() { super(); } }

    测试

    插入数据

    /** * 使用 one-many 的时候 无论 那个先保存,都是先创建然后在更新 * 在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, * 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句. 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了. 单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句. 因为 n 的一端在插入时不会同时插入外键列. */ @Test public void testOntoManyPersist(){ Order order1 = new Order("O-AA"); Order order2 = new Order("O-BB"); Customer customer = new Customer("GGG", "GGG@123.com", 25, new Date()); customer.getOrders().add(order1); customer.getOrders().add(order2); order1.setCustomer(customer); order2.setCustomer(customer); manager.persist(customer); manager.persist(order1); manager.persist(order2); }

    输出SQL语句:

    Hibernate: insert into JPA_CUSTOMER (age, birth, createTime, email, last_name) values (?, ?, ?, ?, ?) Hibernate: insert into jpa_order (customer_id, o_name) values (?, ?) Hibernate: insert into jpa_order (customer_id, o_name) values (?, ?)

    数据库:

    mysql> select * from jpa_customer; +----+-----+-------+---------------------+-------------+-----------+ | id | age | birth | createTime | email | last_name | +----+-----+-------+---------------------+-------------+-----------+ | 1 | 25 | NULL | 2017-03-12 20:04:15 | GGG@123.com | GGG | +----+-----+-------+---------------------+-------------+-----------+ 1 row in set mysql> select * from jpa_order; +----+--------+-------------+ | id | o_name | customer_id | +----+--------+-------------+ | 1 | O-AA | 1 | | 2 | O-BB | 1 | +----+--------+-------------+ 2 rows in set

    读取数据

    //查询,默认是懒加载的在OneToMany(fetch=FetchType.EAGER)变成了左外连查询 @Test public void testOntoManyFind(){ Customer customer = manager.find(Customer.class, 14); System.out.println(customer.getLastName()); System.out.println(customer.getOrders().iterator().next()); }

    输出: 因为是fetch=FetchType.LAZY设置的懒加载,所

    Hibernate: select customer0_.id as id1_0_0_, customer0_.age as age2_0_0_, customer0_.birth as birth3_0_0_, customer0_.createTime as createTi4_0_0_, customer0_.email as email5_0_0_, customer0_.last_name as last_nam6_0_0_ from JPA_CUSTOMER customer0_ where customer0_.id=? GGG Hibernate: select orders0_.customer_id as customer3_0_1_, orders0_.id as id1_6_1_, orders0_.id as id1_6_0_, orders0_.customer_id as customer3_6_0_, orders0_.o_name as o_name2_6_0_ from jpa_order orders0_ where orders0_.customer_id=? Order [id=2, name=O-BB, customer=Customer [id=1, lastName=GGG, email=GGG@123.com, age=25, createTime=2017-03-12 20:04:15.0, birth=null]]

    更新数据

    @Test public void testOntoManyUpdate(){ Customer customer = manager.find(Customer.class, 1); customer.getOrders().iterator().next().setName("O-AA123"); }

    输出SQL语句:

    Hibernate: select customer0_.id as id1_0_0_, customer0_.age as age2_0_0_, customer0_.birth as birth3_0_0_, customer0_.createTime as createTi4_0_0_, customer0_.email as email5_0_0_, customer0_.last_name as last_nam6_0_0_ from JPA_CUSTOMER customer0_ where customer0_.id=? Hibernate: select orders0_.customer_id as customer3_0_1_, orders0_.id as id1_6_1_, orders0_.id as id1_6_0_, orders0_.customer_id as customer3_6_0_, orders0_.o_name as o_name2_6_0_ from jpa_order orders0_ where orders0_.customer_id=? Hibernate: update jpa_order set customer_id=?, o_name=? where id=?

    删除数据

    //直接删除customer的话对应的order的customer_id会被置null //在OneToMany()添加cascade={CascadeType.REMOVE}就会级联删除 @Test public void testOntoManyRemove(){ Customer customer = manager.find(Customer.class, 5); manager.remove(customer); }

    3. 双向一对一

    有两个表和对应的实体类Manager和Department一对一关系 关键点 在Manager.java中配置OneToOne,把关联关系交给Department的表

    @OneToOne(mappedBy="manager") public Department getDepartment() { return department; }

    Department.java配置OnToOne

    @JoinColumn(name="mgr_id",unique=true) @OneToOne(fetch=FetchType.LAZY) public Manager getManager() { return manager; }

    Manager.java

    package com.bart.jpa.beans; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; @Table(name="jpa_mgr") @Entity public class Manager { @GeneratedValue(strategy=GenerationType.AUTO) @Id public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name="m_name",length=20) public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToOne(mappedBy="manager") public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } private int id; private String name; private Department department; public Manager(String name) { super(); this.name = name; } public Manager() { super(); } }

    Department.java

    package com.bart.jpa.beans; import javax.persistence.Column; 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.OneToOne; import javax.persistence.Table; @Table(name="jpa_dept") @Entity public class Department { @GeneratedValue(strategy=GenerationType.AUTO) @Id public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name="d_name") public String getName() { return name; } public void setName(String name) { this.name = name; } @JoinColumn(name="mgr_id",unique=true) @OneToOne(fetch=FetchType.LAZY) public Manager getManager() { return manager; } public void setManager(Manager manager) { this.manager = manager; } private int id; private String name; private Manager manager; public Department(String name) { super(); this.name = name; } public Department() { super(); } }

    测试:

    /* -------双向一对一----- */ //1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象. //可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象 //这说明在不维护关联关系的一方, 不建议修改 fetch 属性. @Test public void testOneToOneFind2(){ Manager mgr = manager.find(Manager.class, 1); System.out.println(mgr.getName()); System.out.println(mgr.getDepartment().getClass().getName()); } /** * 若获取维护关联关系的一方 * 默认情况下,会查询两次,都是左连接链接查询 * 但可以通过 @OntToOne 的 fetch 属性来修改加载策略. */ @Test public void testOneToOneFind(){ Department dept = manager.find(Department.class, 1); System.out.println(dept); System.out.println(dept.getManager().getName()); } /** * 1. 当关联关系交给对方的时候,持久化对象的时候应该先保存不维护的一方 * 2. 否则会出现 多余的update SQL语句 */ @Test public void testOneToOnePerssit(){ Manager m = new Manager("MM"); Department d = new Department("D-AA"); m.setDepartment(d); d.setManager(m); manager.persist(m); manager.persist(d); }

    4. 双向多对多

    item和category,表现为多对多关系 配置多对多的时候注意的地方

    多对多的时候,应该创建一个中间表来管理双方外键

    Item.java,把关联关系交给Category来管理

    @ManyToMany(mappedBy="items")//关联关系交给Category来维护 public Set<Category> getCategorys() { return categorys; } public void setCategorys(Set<Category> categorys) { this.categorys = categorys; }

    Category.java,管理关联关系

    使用 @ManyToMany 注解来映射多对多关联关系 使用 @JoinTable 来映射中间表 1. name 指向中间表的名字 2. joinColumns 映射当前类所在的表在中间表中的外键 2.1 name 指定外键列的列名 2.2 referencedColumnName 指定外键列关联当前表的哪一列 3. inverseJoinColumns 映射关联的类所在中间表的外键

    @JoinTable(name="category_item", joinColumns={@JoinColumn(name="c_id",referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="i_id",referencedColumnName="id")} ) //使用 @ManyToMany 注解来映射多对多关联关系 //使用 @JoinTable 来映射中间表 //1. name 指向中间表的名字 //2. joinColumns 映射当前类所在的表在中间表中的外键 //2.1 name 指定外键列的列名 //2.2 referencedColumnName 指定外键列关联当前表的哪一列 //3. inverseJoinColumns 映射关联的类所在中间表的外键 @JoinTable(name="category_item", joinColumns={@JoinColumn(name="c_id",referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="i_id",referencedColumnName="id")} ) @ManyToMany public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; }

    测试:

    /* -------双向多对多----- */ @Test public void testEhCache(){ Customer customer = manager.find(Customer.class,1); System.out.println(customer); transaction.commit(); //6. 关闭factory entityManagerFactory.close(); //7. 关闭manager manager.close(); //1.创建EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName); //2.创建EntityManager manager = entityManagerFactory.createEntityManager(); //3.开启事务管理 transaction = manager.getTransaction(); transaction.begin(); customer = manager.find(Customer.class,1); System.out.println(customer); } /* -------双向多对多----- */ @Test public void testManyToMany(){ Item i1 = new Item("I-1"); Item i2 = new Item("I-2"); Category c1 = new Category("C-1"); Category c2 = new Category("C-2"); i1.getCategorys().add(c1); i1.getCategorys().add(c2); i2.getCategorys().add(c1); i2.getCategorys().add(c2); c1.getItems().add(i1); c1.getItems().add(i2); c2.getItems().add(i1); c2.getItems().add(i2); manager.persist(i1); manager.persist(i2); manager.persist(c1); manager.persist(c2); }
    转载请注明原文地址: https://ju.6miu.com/read-36877.html

    最新回复(0)