当前位置: 首页 > 工具软件 > Literate > 使用案例 >

Hiberante学习=一对一+多对一+级联/N+1+缓存/事务+HQL/SQL+list/literate

颜修真
2023-12-01
注意变量的公用,私用,一般来说比较推荐私用(private);
one to many 一般默认多的一方设置外键


2016.3.1
1.一对多关联



如果我们使用的是one to many,既然不能在one端,插入多的内容,又为何还要设置set呢??
经过bug检查,发现原来的问题在于之前的
1.数据库的表无法删除(可能是之前建表时触发了什么,可以从无法写入新person中判断)
2.person中的set<car>没有初始化,故无法直接使用getSet


总结:1.遇到bug时,要分析hibernate报错的语句,虽然这很无奈,但这没办法。
      2.学会找出抓住问题的核心,不要老是兜圈子
      3.学会从文档中获得关键的权威的代码,以及参考网上的优秀的代码


2.级联与加载
2016.3.5


cascade = cascadeType.(remove , persist , merge ,refresh , all);
fetch = fetchType.(lazy , eager);

如果在一对多的双向关联中,一端默认为fetchType.lazy(默认不加载多端),而多端默认为fetchType.eager(默认加载一端);
如果我在一端和多端都设置了cascadeType.remove,那么当删除多端的一条记录时,会连带删除一端的记录,而一端的记录又与多端的记录cascadeType.remove,
所以最后可能导致多端的多条记录不见。

fetch指的是要不要加载时顺带关联的记录也加载。

3.缓存与事务

缓存:分为一级,二级,查询(三级缓存)
一级:session里面,属于事务范围
二级:sessionFactory里面,一般适用于重复查询QL语句(比如我想要从一个表中找出Id为1的那条记录,那么第二次重复查询时hibernate就会从sessionFactory中直接拿)
      属于进程范围或者集群范围,即当一个进程或应用中,所有事务都可使用的缓存,相对比一级缓存范围更广。
查询缓存:即Query缓存,相对于二级缓存只能对Id查询进行缓存,query缓存主要针对条件查询。

启动二级缓存可以查阅资料
一级缓存一般不会出现事务并发的三种问题:dirty read 脏读,unrepeatable read 不可重复读,幻读。
二级缓存会出现上述三种问题
查询缓存,目前尚不会,因为表的记录一更新或删除,缓存会被清除。


dirty read:B事务尚未提交,A事务就已读到其修改的数据。
unrepeatable read: B事务提交后,A事务读到其更新的数据,导致前后数据不一样。(可用悲观锁 或 乐观锁 解决)
幻读:B事务提交插入操作后,A事务的所查询的数目更新,比之前多,数据不一致。


悲观锁:让数据库为访问的记录加“锁”,只有当该事务访问完,其他事务才可以访问该记录。
乐观锁:使用@version标记记录的版本,每次修改完,记录的version自增1。A事务更改前记录的版本为0,
由于B事务的操作,记录发生改变,version自增长为1,A事务即将提交时发现记录的前后的版本不一样,便会发出异常。


4.一对一
2016.3.6



一对一主键的单向关联,实体两端都不能设置Id的生成器如generatedType.AUTO,尤其在@primaryKeyJoinColumn端上,因为其Id生成策略受从表的影响,与从表对应。
这样一来,如果主表的记录与从表的记录没有一一对应的关系,那么主表的记录是无法插入的。


注意:hibernate已经完成@primaryKeyColumn的更新,替为@MapsId(复合主键,指连Id名称也一样)。

  使用一对一关联时,可以使用@primaryKeyJoinColumn但必须结合下面代码操作,否则hibernate不会关联两个Id。

   @OneToOne(cascade = CascadeType.ALL)//@MapsId
   @PrimaryKeyJoinColumn
   public car getCars(){
    return cars;
   }
   
   public void setCars(car cars){
    this.cars = cars;
   }


   @Id
   @GenericGenerator(name = "foreignKey" , strategy = "foreign" , 
                     parameters =@Parameter(name = "property"  , value = "cars") )//value = “cars”,中的cars指所在类的对应oneToOne的属性。
   @GeneratedValue(generator = "foreignKey")



5.一对多 与 多对多 关联



    建表时的两条铁律:1.需要为主体设置mappedBy 2.cascadeType , fetchType


    双向关联时需要在一旁设置mappedBy.一般都用中间表的形式保存两者的关联。


2016.3.9
6.1+N问题

  
   manyToOne加载时,会默认加载one的一端,此时发出一条条的sql语句,消耗不必要的内存。
   解决方法:1.fetch = fetchType.Lazy(one的一端全部不加载)
             2.left join fetch(一次性加载有对应的one端,需要时再从缓存取)

             3.batchSize(限制每次只能加载one端多少条)


7.list 与 literate
  针对语句 select * from car,
  list会直接加载所有的满足记录,第二次访问相同时不会再从缓存中自动取
  literate会首先把所有Id值加入缓存,然后再根据需要发出sql语句,第二次访问时,literate会率先从一级缓存中取,如没有再发出sql语句。


8.针对sql以及hql语句。
   
    8.1原生的sql语句与HQL语句不同,
       如:select * from car(sql)等价于 from car(hql),如果hql语句中出现select *,那么会报错,应该要把 * 号换成实体或者字段,属性
       如:hql语句中不能加上分号;
   
    8.2内连接inner join 与外连接 left join,right join
      select p from person p left join car c 错误
      select p form person p left join p.car 正确
    
      注:person与car是一对多关系,如要使用外连接left join后面加上的是person的属性。
             
   8.3关于group by
      8.3.1group by name
+----+-------+
| id | name  |
+----+-------+
|  1 | chen  |
|  4 | chen  |
|  5 | xiao  |
|  8 | huang |
+----+-------+

按name分类 分为三类 chen , xiao , huang

+----+-------+              
| id | name  |               
+----+-------+                 
|  1 | chen  |               
|  4 | chen  |
+----+-------+

+----+-------+
| id | name  |
+----+-------+
|  5 | xiao  |
+----+-------+

+----+-------+
| id | name  |
+----+-------+
|  8 | huang |                
+----+-------+

     8.3.2group by a , b
         先按a进行分组 , 再按b进行分组


   9.如何使用 sql 与 hibernate查询结果:
     hibernate:

        1.       

        Query q = s.createQuery("select count(p.name), p.id from person p group by p.name"); 
         //q.setResultTransformer((Transformers.ALIAS_TO_ENTITY_MAP));
         
         List<Object[]> list1 = q.list();
         for(Object[] p : list1){
         
         System.out.println(p[0]);
         System.out.println(p[1]);
         //System.out.println(p[2]);
         }
         s.close();


       2. 

        Query q = s.createQuery("select p from person p"); 
        //q.setResultTransformer((Transformers.ALIAS_TO_ENTITY_MAP));
         
         List<person> list1 = q.list();
         for(person p : list1){
         
        System.out.println(p.getId);
        System.out.println(p.getName);
        //System.out.println(p[2]);
         }
    s.close();
    

   sql:

     1.  

String sql = "select username , realname from userinfo1;";
         
         try(resultSet = stat.executeQuery(sql)){
             ResultSetMetaData metaData = resultSet.getMetaData();
             int col_len = metaData.getColumnCount();
         
         for(int i = 0; i < col_len; i ++){
                String cols_name = metaData.getColumnName(i+1);
                Object cols_value = resultSet.getObject(cols_name);
                
                System.out.println(cols_name);
                System.out.println(cols_value);
         }}
 

    2.  

 String sql = "select username , realname from userinfo1;";
         
         try(resultSet = stat.executeQuery(sql)){
               while(resultSet.next()){
                     System.out.println(resultSet.getString(1));
                     System.out.println(resultSet.getString(2));
                 }}


         
         
//默认在jdbc.properties后面不能加上;,否则会报错。
//spring会借助IOC帮助我们为还没有实现接口的类的注入实现
//spring还会借助AOP帮助加上业务逻辑(通俗化理解),AOP面向切面编程
       
 类似资料: