Hibernate一对多关联映射,维护端(一方,无外键方)可以进行关联移除,级联删除,级联保存,级联更新,级联刷新。被维护端(多方,外键方),不可以进行关联移除,级联操作,只能级联刷新。
Spring中bean.xml配置
<?xml version="1.0" encoding="UTF-8"?> <!-- 基于注解方式 http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd"> <context:annotation-config /> <context:component-scan base-package="com.entityBean"></context:component-scan> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" /> <property name="username" value="hibernate" /> <property name="password" value="hibernate" /> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="1" /> <!-- 连接池的最大值 --> <property name="maxActive" value="500" /> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="2" /> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="1" /> </bean> <!-- org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean 基于注解的sessionFactroy --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" name="sessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.OracleDialect hibernate.hbm2ddl.auto=update hibernate.show_sql=true hibernate.format_sql=true hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=false hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider </value> </property> <!-- annotatedClasses --> <property name="annotatedClasses"> <list> <value>com.entityBean.one2many.bean.Order</value> <value>com.entityBean.one2many.bean.OrderItem</value> </list> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driven transaction-manager="txManager" /> </beans>
Order(维护端,无外键方,一方)
@Entity @Table(name="T_ORDER") @SuppressWarnings("serial") public class Order implements Serializable { private Integer id; private String bak; private Set<OrderItem> orderItems = new HashSet<OrderItem>(); @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "T_ORDER_GEN") @TableGenerator(name = "T_ORDER_GEN", table = "TB_GENERATOR", pkColumnName = "GEN_NAME", valueColumnName = "GEN_VALUE", pkColumnValue = "T_ORDER_GEN", allocationSize = 1) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getBak() { return bak; } public void setBak(String bak) { this.bak = bak; } /**一对多那方:设置懒加载*/ @OneToMany(mappedBy="order",cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OrderBy(value = "id ASC")/**指明加载OrderItem 时按id 的升序排序*/ public Set<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(Set<OrderItem> orderItems) { this.orderItems = orderItems; } @Override public String toString() { return "Order [id=" + id + ", bak=" + bak + ", orderItems=" + orderItems + "]"; } }
OrderItem(被维护端,有外键方,多方)
@Entity @Table(name="T_ORDERITEM") @SuppressWarnings("serial") public class OrderItem implements Serializable { private Integer id; //不能定义关联的列 //private Integer order_id; private String bak; private Order order; @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "T_ORDERITEM_GEN") @TableGenerator(name = "T_ORDERITEM_GEN", table = "TB_GENERATOR", pkColumnName = "GEN_NAME", valueColumnName = "GEN_VALUE", pkColumnValue = "T_ORDERITEM_GEN", allocationSize = 1) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getBak() { return bak; } public void setBak(String bak) { this.bak = bak; } /**级联刷新*/ /**optional表示该对象可有可无,它的值为true表示该外键可以为null,它的值为false表示该外键为not null*/ @ManyToOne(cascade=CascadeType.REFRESH,optional=false,fetch = FetchType.LAZY) /**指定外键列(这也表示为所在对象为“关系被维护端”)*/ @JoinColumn(name = "order_id") public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } @Override public String toString() { return "OrderItem [id=" + id + ", bak=" + bak + "]"; } }
OrderService
@Service("orderService") @Transactional public class OrderService { @Resource private SessionFactory sessionFactory; /** 从一方保存 (1:一方与多方关系起来2.保存一方)*/ public void saveFromOne() { Order order = new Order(); order.setBak("订单"); OrderItem orderItem1 = new OrderItem(); orderItem1.setBak("明细1"); orderItem1.setOrder(order); OrderItem orderItem2 = new OrderItem(); orderItem2.setBak("明细2"); orderItem2.setOrder(order); Set<OrderItem> orderItems = new HashSet<OrderItem>(); orderItems.add(orderItem1); orderItems.add(orderItem2); // 关联起来 order.setOrderItems(orderItems); // 保存 sessionFactory.getCurrentSession().persist(order); } public void saveFromOne2() { Order order = new Order(); order.setBak("订单"); OrderItem orderItem1 = new OrderItem(); orderItem1.setBak("明细1"); // 多方关联一方 orderItem1.setOrder(order); OrderItem orderItem2 = new OrderItem(); orderItem2.setBak("明细2"); // 多方关联一方 orderItem2.setOrder(order); // 一方关联多方 order.getOrderItems().add(orderItem1); order.getOrderItems().add(orderItem2); sessionFactory.getCurrentSession().persist(order); } /** 多方关联保存,先保存依赖的一方,这样会省略update sql提高效率*/ public void saveFromMany() { Order order = new Order(); order.setBak("订单"); OrderItem orderItem1 = new OrderItem(); orderItem1.setBak("明细1"); orderItem1.setOrder(order); OrderItem orderItem2 = new OrderItem(); orderItem2.setBak("明细2"); orderItem2.setOrder(order); // 1.先保存无外键方 sessionFactory.getCurrentSession().persist(order); // 2.再保存有外键方 sessionFactory.getCurrentSession().persist(orderItem1); sessionFactory.getCurrentSession().persist(orderItem2); } // 存在n+1问题 public Order getOrderByID(Integer orderid) { Order order = (Order) sessionFactory.getCurrentSession().get( Order.class, orderid); // !!!!!因为是延迟加载,通过执行size()这种方式获取订单下的所有订单项 order.getOrderItems().size(); return order; } // inner join 连接解决n+1问题 根据订单id查询订单和明细 public List getOrderByIDNoN_1(Integer orderid) { List orders = sessionFactory .getCurrentSession() .createQuery( "select DISTINCT o from Order o inner join fetch o.orderItems where o.id='" + orderid + "' order by o.id").list(); return orders; } // 查询所有订单和明细 public List getAllOrder() { List result = sessionFactory .getCurrentSession() .createQuery( "select DISTINCT o from Order o inner join fetch o.orderItems order by o.id") .list(); return result; } /** * 被维护端(多方,外键方) *被维护端,无法移除关系,移除关系会报错 */ public void removeRelationFromBeMaintained (Integer orderItemId) { OrderItem orderItem = (OrderItem) sessionFactory.getCurrentSession() .get(OrderItem.class, orderItemId); orderItem.setOrder(null); sessionFactory.getCurrentSession().persist(orderItem); } /** *维护端(一方,无外键方) *维护端:可以移除关系 */ public void removeRelationFromMaintained(Integer orderid) { sessionFactory.getCurrentSession().delete( sessionFactory.getCurrentSession().get(Order.class, orderid)); } /**从被维护端删除,不能删除维护端*/ public void deleteFromNoMaintained(Integer orderItemId) { sessionFactory.getCurrentSession().delete( sessionFactory.getCurrentSession().get(OrderItem.class, orderItemId)); } /**从维护端删除,级联删除*/ public void deleteFromMaintained(Integer id) { sessionFactory.getCurrentSession().delete( sessionFactory.getCurrentSession().get(Order.class, id)); } /**删除:双边删除*/ public void deleteFromBothSide(Integer orderId, Integer orderitemId) { //1.先删除有外键方(被维护端) sessionFactory.getCurrentSession().delete( sessionFactory.getCurrentSession() .get(OrderItem.class, orderitemId)); //2.再删除无外键方(维护端) sessionFactory.getCurrentSession().delete( sessionFactory.getCurrentSession() .get(Order.class, orderId)); } }
测试类:
public class OrderServiceTest { private static OrderService orderService; @BeforeClass public static void setUpBeforeClass() throws Exception { try { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "beans.xml"); orderService = (OrderService) applicationContext .getBean("orderService"); } catch (RuntimeException e) { e.printStackTrace(); } } @Test public void saveFromOne(){ orderService.saveFromOne(); } @Test public void saveFromOne2() { orderService.saveFromOne2(); } @Test public void saveFromMany() { orderService.saveFromMany(); } @Test public void getOrderByID() { Order order=orderService.getOrderByID(1); System.out.println(order); } @Test public void getOrderByIDNoN_1() { List orders = orderService.getOrderByIDNoN_1(1); for (Order o : (List<Order>) orders) { System.out.println(o.getBak()); for (OrderItem r : (Set<OrderItem>) o.getOrderItems()) System.out.println(r.getBak()); } } @Test public void getOrderAll() { List orders = orderService.getAllOrder(); System.out.println(orders.size()); for (Order o : (List<Order>) orders) { System.out.println(o.getBak()); for (OrderItem r : (Set<OrderItem>) o.getOrderItems()) System.out.println(r.getBak()); } } @Test public void removeRelationFromBeMaintained () { orderService.removeRelationFromBeMaintained(1); } @Test public void removeRelationFromMaintained(Integer orderid) { orderService.removeRelationFromMaintained(1); } @Test public void deleteFromMaintained(Integer orderItemId) { orderService.deleteFromMaintained(1); } @Test public void deleteFromNoMaintained(Integer orderItemId) { orderService.deleteFromNoMaintained(1); } @Test public void deleteFromBothSide() { orderService.deleteFromBothSide(1, 2); } }
表主键自增对照表SQL
create table TB_GENERATOR ( GEN_NAME VARCHAR2(255), GEN_VALUE NUMBER(10) )
一对多:数据表关系映射图