注意变量的公用,私用,一般来说比较推荐私用(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面向切面编程