hibernate知识点回顾

来源:互联网 发布:网络公选课刷课软件 编辑:程序博客网 时间:2024/06/11 12:35

1.当碰到session关闭时的异常时,解决方法是扩大session的作用域(在spring中补充)。

2.数据的持久化指的是将数据在持久态和瞬时态之间转换的一种机制,持久化的主要应用是将内存中的对象存储在关系型数据库中,或是磁盘文件、XML数据文件中。

3.实体类的配置文件,id表示主键,generator表示主键生成方式。如Student.hbm.xml

<hibernate-mapping package="com.bjsxt.po"><class name="Student"><id name="sid"><!--id表示主键--><generator class="native"></generator><!-- generator表示生成自增主键 --></id></hibernate-mapping>
4.Hibernate中建立configuration对象,可以用

Configuration conf = new Configuration();//创建对象,这是不加注解的Configuration cfg = new AnnotationConfiguration();//使用了注解得用这个对象,只有这句不同,其余都一样。conf.configure();//读取配置文件。
configuration对象是用来进行配置信息的管理,生成SessionFacyory。默认情况下读取classpath下的hibernate.cfg.xml文件。即src下的hibernate.cfg.xml

5.注解中@Entity的全名是javax.persistence.Entity,而不是hibernate的entity,从这儿可以看出JPA中是个标准,而hibernate是它的实现。注解是在标准中实现。
hibernate中主键的注解为“@Id”,并且约定俗成的在getId()方法上边。因为实体类中的属性都被设置为private,不能直接获取,只能通过get方法得到。符合java的规范。若写到field上,破坏了java的封装性。

@Entity  //表示实体类,对应数据库的一张表public class Teacher {private int id;private String name;@Id  //表示主键@GeneratedValue //表示生成的主键为自增列public int getId() {return id;}public void setId(int id) {this.id = id;}}
不加注解和加了注解的实体类在hibernate.cfg.xml中引入方法不一样

<mapping resource="com/bjsxt/po/User.hbm.xml" /><!--没加注解--><mapping class="com.bjsxt.po.Teacher" /><!--加了注解-->
还有读取配置文件的对象也不一样。

Configuration conf = new Configuration();//创建对象,这是不加注解的Configuration cfg = new AnnotationConfiguration();//使用了注解得用这个对象,只有这句不同,其余都一样。
从这儿可以看出使用注解更简单。

6.对于先建表还是先建类的问题,理论上来说,先建类符合面向对象的思想,可以用hibernate生成相应的类而不用管具体的数据库是什么。但在实际工作中,往往是先建表后建类,因为要考虑到数据库优化的问题,比如建索引、建中间表等。

7.hibernate的原理大致为生成读取hibernate.cfg.xml配置文件的Configuration对象,再根据resource生成相应的表。

8.注解生成表名和类名不同可以用table属性

@Entity@Table(name="tecch")public class Teacher {private int id;}
9.当一个表中已经存在主键,但不是我们想要的时,可以尝试使用联合主键。将这两个主键封装成一个类,然后再在其它类中引用,根据该类的对象生成唯一的实体类。如可把Student的id和name写成一个类StudentPK(主键类),然后在Student中引入该主键类即可。但使用联合主键时要实现serilable接口,还得重写equals和hashcode方法。但联合主键用的不多,尽量别用。

10.hibernate中session可以管理数据库,即实现增删改查。获取session有两个方法

Session session = session.getCurrentSession();//获取当前session,若没有,则创建新的,此时session无需关闭Session session = SessionFactory.openSession();//这是每次都创建新的session,不管有没有session存在,此时session需关闭。session.close()//session提交后自动就close,因此就无需再写多余的close方法。session.getTransaction().commit();//提交方法
这可以界定事务边界。

但若是这样

Session session = SessionFactory.openSession();//先开启新sessionSession session2 = session.getCurrentSession();//获取当前session
会发现这两个session不同。所以说这两种方法不能混用。因为Session是接口,getCurrentSession是接口的实现。并且还有session是否需要手动关闭的问题。

11.session的save方法可以把对象由瞬时态(Transient)变为persistent(持久态)

12.session的get和load方法区别。如

Teacher t = (Teacher)session.load(Teacher.class,1);Teacher t = (Teacher)session.get(Teacher.class,1);
使用时写法一样。但
load返回的是代理对象,只有真正用到对象的内容时才发出sql语句。
get是直接从数据库加载,不会延迟。
无论是get还是load方法都是先去一级缓存中去找,找不到再去数据库找。

13.在设置注解时,同一实体类中最好设置的位置一样,要么都在属性上边设置(虽然与java封装性违背,但看起来整齐),要么都在get方法上设置,否则会报

java.lang.ExceptionInInitializerErrorCaused by: org.hibernate.MappingException: Could not determine type for: com.bjsxt.po.User, for columns: [org.hibernate.mapping.Column(user)]
这样的错误,就是找不到对应的字段。

14.

<many-to-one name="xxx" unique="true">
表示虽然为多对一,但unique(“唯一”的意思)为true,总体表示一对一

15.mappedBy表示放弃外键维护权,用于双向外键关联中。只要有双向关联,就一定要设置mappedBy.如Husband和Wife为一对一,则

@Entity@Table(name="t_husband")//生成的数据库名字public class Husband{private int hid;@OneToOne(mappedBy="husband")//这里要注意mappedBy="husband"中的husband并不是类名Husband,而我们平时理解的是Wife类中的一个Husband属性,也不是很准确。更准确地说法是Wife类中的getHusband,//与get后的名相同。而一般我们设置的属性名和get、set方法后的一致。所以认为是Wife类中的一个Husband属性也可以。private Wife wife;//get/set方法省略}public class Wife{private int hid;@OneToOneprivate Husband husband;//get/set方法省略}
表示外键由wife这一端维护。即在wife这个表中,还有一个字段名husband_hid.在数据库中不需要两边都设外键,只要一边有就行。否则删表时由于有外键循环关联删不掉。
而在xml中则是这样设置。Husband.hbm.xml

<one-to-one name="wife" property-ref="husband" /><!--表示外键由Wife管理。这种xml配置只要会读即可,掌握简单的annotation。-->
16.双向外键映射和单向外键映射生成的数据库完全一样,区别在于java程序中,双向映射可以通过一方找到另一方。单向映射只能由特定一方找到另一方。

17.在一对多中,设计数据库时,在多的一方加外键。即在一的一方只是它设置了多少属性,数据库就有多少字段。而在多的一方,则是多一个外键。

18.而在多对多中,为了简化操作,常常设置一个中间表,形成两个一对多,这样比较好处理。

19.1+N问题常出现在ManyToOne中,在查询的时候,如果N对1的一方的fetch=FetchType.EAGER,本来只需要取Many里的对象属性,可是many里关联的对象都会单独再发一条语句取关联对象的属性。会把被关联的对象一起取出来。解决方法是设置fetch=FetchType.LAZY

20.一级缓存是session级别的缓存,只能在session内部使用。二级缓存是sessionFactory级别的缓存,所有的session可以共用。

21.乐观锁与悲观锁
悲观锁是指假设并发更新冲突会发生,所以不管冲突是否真的会发生,都会使用锁机制。悲观锁是在使用了数据库的事务隔离机制上,独享占用的资源,以此保证读取数据的一致性。
乐观锁不会锁住任何东西,它不依赖数据库的事务机制,若使用乐观锁,数据库就必须加版本字段。

22.uniqueResult()的用法
当根据查询语句数据库只会返回唯一的一条结果或null时,就可以使用该方法,并且返回类型为Object,可根据实际类型强转。
否则就用list()。
uniqueResult()经常用在登陆校验部分。当返回的实例大于一个的时候会抛出NonUniqueResultException异常。

以前用hibernate写登陆可以这样写

public User get(String id){Session session = HiberUtil.getSession();String hql = "from User u where u.uid = ?";List list = session.createQuery(hql).setString(0,uid).list();if (list.size()==1) {return (User)list.get(0);}else{return null;}}

还得进行判断,比较麻烦。若使用uniqueResult()就会很简单。前提就是保证用户名的唯一性。

public User get(String uid){Session session = HiberUtil.getSession();String hql = "from User u where u.uid = ?";User user = session.createQuery(hql).setString(0,uid).uniqueResult();}
也可用

public User  checkLogin(String username,String pwd){Session  session  = HibUtil.getSession();String hql="from User u where u.name=? and u.pwd=?";User user =(User) session.createQuery(hql).setString(0, username).setString(1, pwd).uniqueResult();return user;}

验证的Action可以这样写

public String checkLogin(){Student stu = sdao.checkLogin(sname, pwd);if(stu==null){//用户名或密码错误this.msg = "用户名或密码错误";return "login";}else{ActionContext.getContext().getSession().put("student", stu);//把stu对象放到session当中,在CourseAction中获取return "welcome";}}

23.在hibernate中多对多的双向映射中使用注解,默认会生成中间表,但中间表名一般可读性不好,所以需要修改。如学生选课的多对多中

Student实体类

@Entity@Table(name="t_stu")public class Student {@Id@GeneratedValueprivate int sid;//学生idprivate String sname;@ManyToMany(mappedBy="setstu")//表示外键由Course管理private Set<Course> setcourse = new HashSet<Course>();//注意,集合的生成方式为set,而不是list//get和set方法省略}
Course实体类

@Entity@Table(name="t_course")public class Course {@Id@GeneratedValueprivate int cid;//课程idprivate String cname;@ManyToMany@JoinTable(name="stu_course", //自定义的中间表的名字,因为默认的可读性不好joinColumns={@JoinColumn(name="cid")}, //中间表中字段,与Course的cid关联inverseJoinColumns={@JoinColumn(name="sid")} //中间表中字段,与Student的sid关联)private Set<Student> setstu = new HashSet<Student>();//get和set方法省略}
然后会生成平时习惯用的表。

24.多对多的双向关联中,一般是修改频繁的那一端往往放弃外键的维护权。如User和Role,在User那一方加mappedBy,表示User这端放弃外键维护。

25.在项目中使用dwr后,可以使用dwr测试action中的各种方法,具体是在浏览器输入:……/项目名称/dwr/
(注意dwr后的斜杠不能丢,否则报错)

26.当出现错误

Caused by: java.lang.ClassNotFoundException: javax.persistence.Entity
这往往是缺少ejb3-persistence.jar包所致,这是实体类不能持久化的缘故。导入相应包即可。



原创粉丝点击