HIbernate 知识点
HibernateORM(对象关系映射O-Rmapping)框架
对象-持久化-数据库(关系型数据库)
对象-关系
内存中的对象与数据库中字段的对应关系。
持久化标示---关系模型中的主键(用id来配)
Hibernate的三种对象状态:
1.transient:neverpersistent,notassociatedwithanySession瞬时状态
2.persistent:associatedwithauniqueSession持久化状态
3.detached:previouslypersistent,ntoassociatedwithanySession脱管状态
瞬时状态:内存中的对象在数据库中没有与之对应的记录,并且此对象也没有纳入Session的管理,那么此时对象的任何变化都不会发出SQL语句,也就是O和R没有联动。
(判断对象和数据库是否关联的重要标准就是判断对象是否具有持久化标示)
持久化状态:内存中的对象在数据库中有与之对应的记录,并且对象纳入Session管理,此时O的任何变化就会自动的发出SQL语句,也就是说对象和数据库是实时联动。
脱管状态:内存中的对象在数据库中有与之对应的记录,但是对象没有纳入Session管理,那么此时对象的任何变化都不会发出SQL语句,也就是O和R没有联动。
对对象设置了持久化标示,此时由于此标示在数据库中已经存在,则user变为托管状态,用Update自动的更新修改的数据。
//在get方法执行时,首先搜索缓存中是否存在持久化标示为1的对象,如果存在则直接从缓存中获取此对象,否则说明不存在,那么立即发送SQL进行查询,但是此处的缓存是Session级别的,出了本Session,持久化对象就失效了,我们称之为一级缓存。并不是每次修改都执行SQLupdate语句,它会自动查询改之前和改之后内存中的对象是否一致,不一致才执行update。(二级缓存:SessionFactory,所有服务器公用一个。)
pubic void testQuery(){ Session session=null; try{ session=HibernateSessionFactory.getSession(); session.beginTransaction(); user=(User)session.get(User.class,1);//根据指定的标识符返回持久化对象,如果找不到返回//null,User.class:Class;1:Serializable(id) System.out.println(user.getUsername()+":"+user.getPassword()); session.getTransaction().commit(); }catch(HibernateException e){ if(seession.getTransaction().isActive()) session.getTransaction.rollback(); e.printStackTrace(); }finally{ HibernateSessionFactory.closeSession(session); } }
------------------------
//load(class,id)方法:根据指定的标识符返回持久化对象。
代理模式(中介)
属于延迟加载,默认不发送SQL语句,只由当调用此对象的成员时才发送SQL语句。
如果要搜索的对象不存在,get报空指针异常,load报找不到对象异常。
----------------
//建议再删除之前先查询,删除完毕后user变成瞬时状态
删除:delete()
(1)user.setId(1);//1:已经存在,属于脱管状态 session.delete(user);//删除脱管对象对应的数据库记录删除 (2)user=session.get(User.class,2);//2:已经存在,user:持久化状态 session.delete(user); user.setId(7);//变为脱管状态 user.setUsername("asdgadfghad");// session.get(User.class,user.getId());//变为持久化状态 ---------------------------------------- //user1脱管状态 user1.setId(12); user1.setUsername("大明"); user1.setPassword("ddasdg"); //user2脱管状态 user2.setId(12); user2.setUsername("二明"); user2.setPassword("asgas"); /* 这样会抛出异常 session.update(user1); session.update(user2); */ session.merge(user1);//不改变状态,不会从脱管状态变为持久化状态 session.merge(user2); ------------------------------------- Hibernate语句去创建表 Configuration cfg=new Configuration().configure(); SchemaExport se=new SchemaExport(cfg); se.create(true,true);
-----------------------------
表和表的关系---对象和对象的关系
7种常见的关系:
单向
1-1:外键1-1和主键1-1
1-N
N-1
N-N
双向:
1-1
1-N(N-1)
N-N
(1)1-1
UserInfo--
Login--
(2)N-1
t_room:
idroom_name
user:
idusernameroomId
-------------------------------------------------------
使用List:
<listname="students"table="t_teacher_student"cascade="save-update">
<keycolumncolumn="t_id"></key>
<indexcolumn="stu_index"></index>
<many-to-manyclass="student"column="s_id"></many-to-many>
</list>
-------------------------------------------------------
继承映射(InheritanceMappings)
(1)每个类分层结构一张表(tableperclasshierarchy)
(2)每个子类一张表(tablepersubclass)
(3)每个具体类一张表(tableperconcreteclass)
---------------
(1)每个类分层结构一张表
Person-->Student
-->Worker
idnameagesexschoolfactorytype
1aaa22男清华S
2bbb24男首钢W
<discriminator>鉴别器
person.hbm.xml:
<hibernate-mapping package="vo"> <class name="Person" table ="t_person"> <id name="id" column="id"> <generator class="native"></generator> </id> <discriminator column="type" type="String"></discriminator> <property name="name" unique="true" not-null="true" column="name"/> <property name="age" column="age" length="32"/> <property name="sex" column="sex"/> <subclass name="Student" discriminator-value="STUDENT"> <property name="school" column="school" length="60"/> </subclass> <subclass name="Worker" discriminator-value="WORKER"> <property name="factory" column="factory"></property> </subclass> </class> </hibernate-mapping>
------------------------------
(2)每个子类一张表
t_person
idnameagesex
t_student
idschoolpid
t_worker
idfactorypid
--------
person.hbm.xml:
<hibernate-mapping package="vo"> <class name="Person" table ="t_person"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" unique="true" not-null="true" column="name"/> <property name="age" column="age" length="32"/> <property name="sex" column="sex"/> <joined-subclass name="Student" table="t_student"> <key column="id"></key> <property name="school" not-null="true"></property> </joined-subclass> <joined-subclass name="Worker" table="t_worker"> <key column="id"></key> <property name="facotry" not-null="true"></property> </joined-subclass> </class> </hibernate-mapping>
---------------------
(3)每个具体类一张表
t_person
t_student
idnameagesexschool
t_worker
idnameagesexfactory
--------
person.hbm.xml:
<hibernate-mapping package="vo"> <class name="Person" table ="t_person" abstract="true">------t_person不会生成-------- <id name="id" column="id" type="String"> <generator class="uuid"></generator> </id> <property name="name" unique="true" not-null="true" column="name"/> <property name="age" column="age" length="32"/> <property name="sex" column="sex"/> <union-subclass name="Student" table="t_student"> <property name="school" not-null="true"></property> </union-subclass> <union-subclass name="Worker" table="t_worker"> <property name="factory" not-null="true"></property> </union-subclass> </class> </hibernate-mapping>
------------------------------------------------
项目经验:
数据库的后台约束,尽量放到前台去验证,如:验证申请/修改的用户名是否数据库中已经存在,都在前台验证。
------------------------------------------------------------------------------------------------------
HQL(大小写敏感:类中的属性):
(1)select lastName,salary from Employee 注意:lastName,salary :是对象的属性,而不知数据库表中的字段名。等价于(emp:别名): select emp.lastName,emp.salary from Employee emp (2)HQL支持对象导航:查询department.departmentName(department对象中有departmentName属性) select emp.lastName,emp.salary,emp.department.departmentName from Employee emp hibernate会总动建立多表连接查询(where ....) (3)内连:(与前面的语句等价) select emp.lastName,emp.salary,dept.departmentName from Employee emp inner join emp.department dept (4)-----------where------- select emp.lastName,dept.departmentName from Employee emp,Department dept where emp.department.departmentId=dept.departmentId (5) 左外连接:把左边那个表中不符合条件的数据查询出来 select emp.lastName,dept.departmentName from Employee emp left join emp.department dept 右外连接:把右边那个表中不符合条件的数据查询出来 select emp.lastName,dept.departmentName from Employee emp right join emp.department dept 内连接:发送等值连接条件 select emp.lastName,dept.departmentName from Employee emp join emp.department dept with可以在join 后面设置条件,如: select emp.lastName,dept.departmentName from Employee emp join emp.department dept with dept.id=20 注意(返回一个对象,但需要重写构造器): select new Employee(emp.lastName,dept.departmentName) from Employee emp join emp.department dept (6)子查询 select e.lastName from Employee e where e.salary = ( select max(emp.salary) //,min(emp.salary),avg(emp.salary),sum(emp.salary) from Employee emp ) (7)分组查询+条件(having) select avg(emp.salary) emp.department.departmentId from Employee emp group by emp.department.departmentId having avg(emp.salary)>=5000 (8)current_date() 当前日期:2009-06-11;current_time()当前时间:07:27:07 select emp.hireDate,current_date(),current_time() from Employee emp (9)to_char和to_date to_char: select to_char(emp.hireDate,'YYYY MM DD') from Employee emp where to_char(emp.hireDate,'YYYY-MM-DD') between '1990-01-01' and '1998-01-23' to_date: select emp.hireDate from Employee emp where emp.hireDate between to_date('1990-01-01') and to_date('1998-01-23') (10)order by 排序 select emp.lastName,emp.salary from Employee emp order by emp.salary DESC (11)ROWNUM 很重要 select aa.*,ROWNUM from ( select last_name,salary,d.department_name from employees e,departments d where e.department_id=d.department_id order by salary DESC ) aa where RoWNUM<=5 ------------主要用于分页 List list=session.createQuery("select emp.lastName,emp.salary from Employee emp order by emp.salary DESC").setFirstResult(0).setMaxResults(5).list(); (12)自查询(工人和上司) SQL语句: select e.last_name,m.last_name from emploees e,employees m where e.manager_id=m.employee_id HQL语句: select emp.lastName,manager.lastName from Employee emp join emp.manager manager (13)查询跟“King”在同一部门的员工个数 SQL语句: select count(*) from Employee e where e.department_id= ( select emp.department_id from Employee emp where emp.lastName='King' ) HQL语句: select distinct e.manager.employees.size from Employee e where e.lastName='King'
(14)HQL语句传参:
第一种:
Listlist=session.createQuery("
fromEmployeeempwhereemp.salarybetween?and?
").setParameter(0,5000.0).setParameter(1,10000.0).list();
第二种:
Listlist=session.createQuery("
fromEmployeeempwhereemp.salarybetween:sale1and:sale2
").setParameter(sale1,5000.0).setParameter(sale2,10000.0).list();
(15)迭代器Iterator:
Iteratorit=session.creaetQuery("fromEmployee").iterate();
while(it.hasNext()){
Employeeemp=(Employee)it.next();
System.out.println(emp.getLastName()+"-"+emp.getSalary());
}
------------------------------------------------------------------------
一级缓存:Session级别(进程级别)
二级缓存:SessionFactory应用级别
--------------------------------------------------------------------------
NativeSQL(原生SQL)
(1)单表查询
List<Employee>l=session.createSQLQuery("select(emp.*)fromemployeesem").
addEntity("emp",Employee.class).list();
(2)多表查询
addEntity
addJoin
----------------------------------
处理大批量的更新/删除操作(不适合用hibernate操作),建议和数据库保持最短的联系:
Connnectionconn=session.getConnection();
PreparedStatementps=conn.prepareStatement("deletefromemployees");
-----------------------------------------
往HQL中传递数组参数:
Integer[]deptIds={50,60,90,10};
List<Department>list=session.createQuery("
fromDepartmentdeptwheredept.idin(:deptId)")
.setParameterList("deptId",deptIds)
.list();
--------------------------
get/load都是应用一级缓存(session)
即,内存中有原来的对象,不会重发SQL语句。
-----------------------------
悲观锁乐观锁(表级锁)
----
ANSI92
数据库的隔离级别:
四种:
更新丢失:两个事务同时更新更新一条数据
不可重复读:
脏读:
幻读:读到了别人插入的数据
脏读幻读不可重复读
(1)未提交读YYY
(2)提交读NYY
(3)可重复读NYN
(4)序列化NNN
---------------------------------------
二级缓存(thesecondlevelcache)
hibernate.cfg.xml:
<property name="cache.use_second_level_cache">true</property> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> ---------------------------------------- 清空二级缓存中的Employee实体: HibernateSessionFactory.getSessionFactory().evict(Employee.class);
-----------------------------------------------------------------------
//用户登录isLogin(User user) private static final String ISLOGIN_HQL ="select count(*) from User user where user.username=? and user.password=?"; //判断此用户是否存在 private static final String QUERYUSERNAME_HQL ="select count(*) from User user where user.username=?"; ----------------------------- struct 与 hibernate 结合实例: 过滤器: public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException,ServletException{ Session session=null; try{ session=HibernateSessionFactory.getSession(); session.beginTransaction(); chain.doFilter(request,response); session.getTransaction().commit(); }catch(HibernateException e){ if(session.getTransaction().isActive()){ session.getTransaction().roolback(); } e.printStackTrace(); }finally{ HibernateSessionFactory.closeSession(); } } DAO实现:如: public boolean delete(String uid){//删除用户记录 boolean b=false; Session session=HIbernateSessionFactory.getSession(); User user=(User)session.load(User.class,uid); b=session.delete(user); return b; }
Hibernate的加锁模式:
LockMode.NONE:有缓存用缓存,没缓存则从数据库读
LockMode.READ:直接从数据库读,不使用缓存数据
LockMode.WRITE:在insertupdate数据的时候,HIBERNATE内部使用的。
以上3种均为HIBERNATE级别的锁,也就是缓存级别的锁。