Hibernate高级应用

单向N-1关联

单向N-1关系,比如多个人对应一个地址,只需从人实体端可以找到对应的地址实体,无须关系某个地址的全部住户。              单向N-1关联只需从N的一端可以访问1的一端。

域模型

从Order到Customer的多对一单向关联需要在Order类中定义一个Customer属性,而在Customer类中无需定义存放Order对象的集合属性。即一个顾客可以对应多个订单。

关系数据模型       

ORDERS 表中的CUSTOMER_ID 参照CUSTOMER 表的主键。


配置关系映射文件(Order.hbm.xml)

many-to-one指明了外键 ,会根据反射机制,找到要和ORDER建立多对一关系的类,该列默认的是可以为空的

<many-to-one name="customer" column="CUSTOMER_ID" class="mypacker.entity.Customer"></many-to-one>

 映射多对一的关联关系,使用many-to-one 来映射多对一的关联关系
  name:多这一端关联的一那一端的属性的名字                                                                                                                        class:一那一端的属性对应的类名
  column:一那一端在多的一端对应的数据表中的外键的名字
  部门的类型

配置持久化类:

public class Order {
	private Integer orderId;
	private String orderName;
	private Customer customer;	
	//单向多对一(如果那个类还有一个对此类的一对多,则这个就是双向的多对一)

save()方法

public void testMany2OneSave(){
		Customer customer = new Customer();
		customer.setCustomerName("AA");	////在Customer表中创建一个CustomerName=AA的数据,ID自动生成
		Order order1 = new Order();
		order1.setOrderName("Order-1");//在Order表中建立Order-1、Order-2两条数据,ID也是自动生成,外键Customer_ID等于上面的AA那条数据的ID
		Order order2 = new Order();
		order2.setOrderName("Order-2");
		//设定关联关系
		//为两条Order对象添加一个Customer对象信息
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		//执行save操作:推荐先插入1的一端,再插入n的一端
		//如果先插入Order,再插入Customer,会产生3条INSERT,2条UPDATE
		//因为在插入多的一端时,无法确定1的一端的外键值,所以只能等1的一端插入后,再额外发送UPDATE语句
		session.save(customer);
		session.save(order1);
		session.save(order2);
		transaction.commit();
	}
Hibernate: 
	    insert 
	    into
	        CUSTOMERS
	        (CUSTOMER_NAME) 
	    values
	        ('AA')	##CUSTOMER_ID为1##
	Hibernate: 
	    insert 
	    into
	        ORDERS
	        (ORDER_NAME, CUSTOMER_ID) 
	    values
	        (Order-1, 1)
	Hibernate: 
	    insert 
	    into
	        ORDERS
	        (ORDER_NAME, CUSTOMER_ID) 
	    values
	        (Order-2, 1)


get()方法

public void testMany2OneGet(){
		//1.若查询多的一端的对象,则默认情况下,只查询了多的一端的对象,而没有查询关联的一的一端的对象
		//获取Order对象时,默认情况下,其关联的Customer对象是一个代理对象
		Order order = (Order) session.get(Order.class,5);
		System.out.println(order.getOrderName());
		//session.close();
		//2.当在需要使用到关联对象的属性时,才发送对应的SQL查询语句
		Customer customer = new Customer();
		System.out.println(customer.toString());
		
		//3.在查询Customer对象时,由多的一端导航一的一端时,若此时session已被关闭,则会发生懒加载异常
	}

控制台打印出SQL语句:

/*
	Hibernate: 
	    select
	        order0_.ORDER_ID as ORDER1_1_0_,
	        order0_.ORDER_NAME as ORDER2_1_0_,
	        order0_.CUSTOMER_ID as CUSTOMER3_1_0_ 
	    from
	        ORDERS order0_ 
	    where
	        order0_.ORDER_ID=?
	*/


update()方法

public void testMany2OneUpdate(){
		Order order = (Order) session.get(Order.class,5);
		order.getCustomer().setCustomerName("AAA");
		//通过orderId=5的那条记录获取对应的customer,而数据库中的那条customer的id=3,所以,costumer表中id=3的那条记录的name变更为AAA
		session.update(order);
		transaction.commit();
	}

控制台打印出SQL语句:

Hibernate: 
    select
        order0_.ORDER_ID as ORDER1_1_0_,
        order0_.ORDER_NAME as ORDER2_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_ 
    from
        ORDERS order0_ 
    where
        order0_.ORDER_ID=5
Hibernate: 
    select
        customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
        customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ 
    from
        CUSTOMERS customer0_ 
    where
        customer0_.CUSTOMER_ID=?
Hibernate: 
    update
        CUSTOMERS 
    set
        CUSTOMER_NAME=? 
    where
        CUSTOMER_ID=?

delete()方法

public void testMany2OneDelete(){
		Customer customer = (Customer) session.get(Customer.class,3);
		//在不设定关联关系的情况下,且1这一端的对象有n的对象在引用,则不能直接删除1这一端的对象
		//也就是说在CUSTOMER表的主键数据在ORDER表中有与之对应的外键数据,如果删掉了CUSTOMER的主键=1的记录,那ORDER表中的外键=1的记录就没法与主表对应了,所以会出错,得先删掉ORDER表中的外键=1的记录,才能删掉CUSTOMER的主键=1的记录
		//org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
		session.delete(customer);
		transaction.commit();
	}


双向1-N关联

对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而使用N的一端控制关联关系。                      双向的N-1关联与1-N关联是完全相同的两种情况。两端都需要增加对关联属性的访问,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合元素为关联实体。  

域模型 

从Order到Customer的多对一双向关联需要在Order类中定义一个Customer属性,而在Customer类中需定义存放Order对象的集合属性。

关系数据模型

ORDERS表中的CUSTOMER_ID参照CUSTOMER表的主键。     

配置关系映射文件

<set name="orders" inverse="true" cascade="delete" order-by="ORDER_NAME DESC">
			<key column="CUSTOMER_ID"></key>	<!-- key指明了ORDER表中的外键 -->
			<one-to-many class="mypacker.entity.Order"></one-to-many><!-- one-to-many指明了和哪个类进行一对多的映射   -->
			</set>
name:多这一端关联的一那一端的属性的名字
column:一那一端在多的一端对应的数据表中的外键的名字
class:一那一端的属性对应的类名


Hibernate_set的3个属性

①<set>元素的inverse属性                                                                                                                                                    在Hibernate中通过对inverse属性的设置来决定是由双向关联的哪一方来维护表和表之间的关系,inverse=false的为主动方,inverse=true的为被动方,由主动方负责维护关联关系。                                                                                                        在没有设置inverse=true的情况下,父子两边都维护父子关系。    

②<set>、<many-to-one>、<one-to-many>都有一个cascade属性,它用于设定级联操作,开发时不建议设定该属性。        常用的取值包括:                                                                                                                                                                  save-update:当通过Session的save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。                                                                                                                    delete:当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。                                                              delete-orphan:删除所有和当前对象接触关联关系的对象。      

③<set>元素的order-by属性,如果设置了该属性,当Hibernate通过selete语句到数据库中检索集合对象时,利用order by子句进行排序。order-by属性中还可以加入SQL函数。                                                                                                                 order-by 中使用的是表的字段名,而不是持久化类的属性名。


配置持久化类

public class Customer {
	private Integer customerId;
	private String customerName;
	//需要把集合进行初始化防止空指针异常
	//声明集合类型时,需使用接口类型,因为Hibernate在获取集合类型时,返回的是Hibernate内置的集合类型,而不是JavaSE一个标准的集合实现
	private Set<Order> orders = new HashSet<Order>(); //双向一对多


save()方法

public void testOne2ManySave(){
		Customer customer = new Customer();
		customer.setCustomerName("GG"); //在Customer表中创建一个CustomerName=GG的数据,ID自动生成
		Order order1 = new Order();
		order1.setOrderName("Order-3");	//在Order表中建立Order-3、Order-4两条数据,ID也是自动生成,外键Customer_ID等于上面的GG那条数据的ID
		Order order2 = new Order();
		order2.setOrderName("Order-4");
		//设定关联关系
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		//为当前Customer对象添加两条Order信息
		customer.getOrders().add(order1);
		customer.getOrders().add(order2);
		//执行save操作:先插入Customer,再插入Order,3条INSERT语句,2条UPDATE语句
		//因为1的一端和n的一端都维护关联关系所以会多出UPDATE
		//可以在1的一端的set节点指定inverse=true来使1的一端放弃维护关联关系
		//建议设定set的inverse=true,建议先插入1的一端,后插入多的一端,好处是不会多出UPDATE语句
		session.save(customer);
		session.save(order1);
		session.save(order2);
		transaction.commit();
	}

get()方法

public void testOne2ManyGet(){
		//对 n 的一端的集合使用延迟加载,在使用集合中的元素时才初始化,所以也会可能抛出懒加载异常
		Customer customer = (Customer) session.get(Customer.class,1);
		//返回的多的一端的集合是Hibernate内置的集合类型,该类型具有延迟加载和存放代理对象功能
		System.out.println(customer.getCustomerName());
	}

update()方法

public void testOne2ManyUpdate(){
		Customer customer = (Customer) session.get(Customer.class,4);
		customer.getOrders().iterator().next().setOrderName("GGG");	
		//把外键CUSTOMER_ID=4的那条数据对应的ORDER_NAME改为GGG,但只是第一条改了
		session.save(customer);
		transaction.commit();
	}

delete()方法

public void testOne2ManyDelete(){
		Customer customer = (Customer) session.get(Customer.class,4);
		//与多对一一样,在不设定关联关系的情况下,且1这一端的对象有n的对象在引用,则不能直接删除1这一端的对象
		//也就是说在CUSTOMER表的主键数据在ORDER表中有与之对应的外键数据,如果删掉了CUSTOMER的主键=1的记录,那ORDER表中的外键=1的记录就没法与主表对应了,所以会出错,得先删掉ORDER表中的外键=1的记录,才能删掉CUSTOMER的主键=1的记录
		session.delete(customer);
	}


HQL: Hibernate查询语言

HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似,在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。

HQL查询包含以下步骤:

1.获取Hibernate Session对象。                                                                                                                                              2.编写HQL语句。                                                                                                                                                                  3.以HQL语句作为参数,调用Session的createQuery方法创建查询对象。                                                                                4.如果HQL语句包含参数,则调用Query的setXxx方法为参数赋值。                                                                                          5.调用Query对象的list()或uniqueResult()方法返回查询结果列表。 

public class UserTest {  
    Session session;  
      
    //junit测试,先执行before,后内容,最后执行after,这样减少重复代码量  
    @Before  
    public void before(){  
        Configuration configuration = new Configuration().configure();  
        SessionFactory sessionFactory = configuration.buildSessionFactory(  
                new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build());  
        session = sessionFactory.getCurrentSession();  //sessionFactory.openSession()  
        session.beginTransaction();  
    }  
      
    @After  
    public void after(){  
        session.getTransaction().commit();  
    }  
      
    @Test  
    public void testAddUser() {  
        User user = new User(1,"张三","abcd",new Date());  
        session.save(user);  
    }  
      
    @Test  
    public void testSelectUserById(){  
//      User user = (User) session.get(User.class, 1);  
        User user = (User) session.load(User.class, 1);  
        System.out.println(user);  
    }  
    @Test  
    public void testUpdate(){  
//      User user = new User(1,"李四1","123",new Date());  
//      session.update(user);  
          
        User user = (User) session.get(User.class, 1);  
        user.setUserName("王二");  
          
        session.update(user);  
    }  
      
    @Test  
    public void testDelete(){  
//      User user = new User(1,"李四1","123",new Date());  
//      session.delete(user);  
          
        User user = (User)session.get(User.class, 2);  
        session.delete(user);  
    }  
      
    @Test  
    public void testSelectAllUser(){  
        String hql = "FROM User ORDER BY id DESC ";  
          
        Query query = session.createQuery(hql);  
        List<User> userLists = query.list();  
        for(User user:userLists){  
            System.out.println(user);  
        }  
    }  
      
    @Test  
    public void testSelectUserName(){  
        String hql = "SELECT u.userName FROM User AS u";  
          
        Query query = session.createQuery(hql);  
        List<String> userLists = query.list();  
        for(String user:userLists){  
            System.out.println(user);  
        }  
    }  
    @Test  
    public void testSelectdUserByUsername(){  
        String hql = "FROM User WHERE userName = :name AND passWord = :psw";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "张三");  
        query.setParameter("psw", "abcd");  
        User user = (User) query.uniqueResult();  
        System.out.println(user);  
    }  
      
    @Test  
    public void testUpdateUsers(){  
        String hql = "UPDATE User SET userName=:name WHERE passWord=:psw";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "麻子");  
        query.setParameter("psw", "123");  
        int order = query.executeUpdate();  
        System.out.println("order :"+order);  
    }  
      
    @Test  
    public void testDeleteUserByUserName(){  
        String hql = "DELETE User WHERE userName = :name";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "张三");  
        query.executeUpdate();  
          
    }  
      
}



猜你喜欢

转载自blog.csdn.net/qq_33800083/article/details/80211655