网站制作现在赚钱么,临沂 网站推广,网站建设百度推广说词,公司网站的ftp是什么Hibernate原理与应用 主要内容 1、引入 2、安装配置 3、基本概念和CURD 4、HQL和Criteria 5、关联映射 6、继承映射 7、集合映射 8、懒加载 9、缓存 10、事务 11、其他 12、Hibernate不适合的场景 13、与JPA的集成(annotation方式) 14、最佳实践 1、引入 模型不匹配(阻抗不匹配…Hibernate原理与应用 主要内容 1、引入 2、安装配置 3、基本概念和CURD 4、HQL和Criteria 5、关联映射 6、继承映射 7、集合映射 8、懒加载 9、缓存 10、事务 11、其他 12、Hibernate不适合的场景 13、与JPA的集成(annotation方式) 14、最佳实践 1、引入 模型不匹配(阻抗不匹配) Java面向对象语言对象模型其主要概念有继承、关联、多态等数据库是关系模型其主要概念有表、主键、外键等。 解决办法 1使用JDBC手工转换。 2使用ORM(Object Relation Mapping对象关系映射)框架来解决主流的ORM框架有Hibernate、TopLink、OJB。 安装配置 下载地址http://www.hibernate.org 将下载目录/hibernate3.jar和/lib下的hibernate运行时必须的包加入classpath中 antlr.jar,cglib.jar,asm.jar,commons-collections.jar,commons-logging.jar,jta.jar,dom4j.jar 配置文件hibernate.cfg.xml和hibernate.propertiesXML和properties两种这两个文件的作用一样提供一个即可推荐XML格式下载目录/etc下是示例配置文件。 可以在配置文件指定 数据库的URL、用户名、密码、JDBC驱动类、方言等。 启动时Hibernate会在CLASSPATH里找这个配置文件。 映射文件(hbm.xml对象模型和关系模型的映射)。在/eg目录下有完整的hibernate示例。 快速开始小例子 基本概念和CURD 开发流程 1由Domain object - mapping-db。(官方推荐) 2由DB开始用工具生成mapping和Domain object。(使用较多) 3由映射文件开始。 基本概念和CURD Domain Object限制 1.默认的构造方法(必须的)。 2有无意义的标示符id主键(可选) 3非final的对懒加载有影响可选 Domain Java Object(User) public class User { private int id; private String name; private Date birthDay; //getter setter… } 1.hbm.xml ?xml version1.0? hibernate-mapping package“cn.itcast.domain class nameUser tableuser id nameid generator classnative/ /id property namename/ property namebirthday”/ /class /hibernate-mapping Java代码 1.初始化代码(只做一次) Configuration cfg new Configuration(); cfg.configure(“config.cfg.xml”); 也可以通过cfg.setProperty设置属性。 SessionFactory sessionFactory cfg.buildSessionFactory(); 2.模板代码 Session session null;Transaction tx null; try{ session sessionFactory.openSession(); tx session.beginTransaction(); //…你的代码save,delete,update,get… tx.commit(); }catch(Exception e){ if(tx !null)tx.rollback();throw e; }finally{ if(session ! null)session.close(); } Session的几个主要方法 1.save,persist保存数据persist在事务外不会产生insert语句。 2.delete,删除对象 3.update,更新对象如果数据库中没有记录会出现异常。 4.get,根据ID查会立刻访问数据库。 5.Load根据ID查(返回的是代理不会立即访问数据库)。 6.saveOrUpdate,merge(根据ID和version的值来确定是save或update),调用merge你的对象还是托管的。 7.lock(把对象变成持久对象但不会同步对象的状态)。 对象状态 瞬时(transient)数据库中没有数据与之对应超过作用域会被JVM垃圾回收器回收一般是new出来且与session没有关联的对象。 持久(persistent)数据库中有数据与之对应当前与session有关联并且相关联的session没有关闭事务没有提交持久对象状态发生改变在事务提交时会影响到数据库(hibernate能检测到)。 脱管(detached)数据库中有数据与之对应但当前没有session与之关联托管对象状态发生改变hibernate不能检测到。 HQL和Criteria HQL(Hibernate Query Language) 面向对象的查询语言与SQL不同HQL中的对象名是区分大小写的除了JAVA类和属性其他部分不区分大小写HQL中查的是对象而不是和表并且支持多态HQL主要通过Query来操作Query的创建方式 Query q session.createQuery(hql); from Person from User user where user.name:name from User user where user.name:name and user.birthday :birthday Criteria Criteria是一种比HQL更面向对象的查询方式Criteria的创建方式 Criteria crit session.createCriteria(DomainClass.class); 简单属性条件如criteria.add(Restrictions.eq(propertyName, value)), criteria.add(Restrictions.eqProperty(propertyName,otherPropertyName)) 基本功能练习 实现UserDao public interface UserDao { public void saveUser(User user); public User findUserById(int id); public User findUserByName(String name); public void updateUser(User user); public void remove(User user); } 实验步骤 1.设计domain对象User。 2.设计UserDao接口。 3.加入hibernate.jar和其依赖的包。 4.编写User.hbm.xml映射文件可以基于hibernate/eg目录下的org/hibernate/auction/User.hbm.xml修改。 5.编写hibernate.cfg.xml配置文件可以基于hibernate/etc/hibernate.cfg.xml修改必须提供的几个参数 connection.driver_class、connection.url、connection.username、connection.password、dialect、hbm2ddl.auto。 6.编写HibernateUtils类主要用来完成Hibnerate初始化和提供一个获得Session的方法这步可选。 7.实现UserDao接口。 关联映射 多对一(Employee - Department) 一对多(Department-Employee) 一对一(room - door) 多对多(teacher - student) 组件映射(User-Name) 集合映射(set, list, map, bag) inverse和cascade(Employee– Department) 多对一(Employee - Department) 映射文件many-to-one name”depart” column”depart_id”/ ER图 关联映射 一对多(Department-Employee) set name”employees” key column”depart_id”/ one-to-many class”Employee”/ /set 一对一(Person - IdCard) 1)基于主键的one-to-one(person的映射文件) id name”id” generator class”foreign”param name”property”idCard/param/generator id one-to-one name”idCard” constrained”true”/ 一对一(Person - IdCard) 2)基于外健的one-to-one可以描述为多对一加unique“true”约束 one-to-one name”idCard” property-ref“person”/ property-ref用于指定关联类的一个属性这个属性将会和本外键相对应 many-to-one name”person” column”person_id” unique”true” not-null”true”/ !-唯一的多对一其实就便成了一对一了-- 关联映射 多对多(teacher - student) 在操作和性能方面都不太理想所以多对多的映射使用较少实际使用中最好转换成一对多的对象模型Hibernate会为我们创建中间关联表转换成两个一对多。 set nameteacher tableteacher_student key columnteacher_id/ many-to-many classStudent columnstudent_id/ /set 关联映射 组件映射(User-Name) 关联的属性是个复杂类型的持久化类但不是实体即数据库中没有表与该属性对应但该类的属性要之久保存的。 component name”name” class”com.test.hibernate.domain.Name” property name”initial”/ property name”first”/ property name”last”/ /component 当组件的属性不能和表中的字段简单对应的时候可以选择实现 org.hibernate.usertype. UserType或 org.hibernate.usertype. CompositeUserType 对于一些不是复杂的实体类我们可以在数据库中没有表与之相对应 这时可选用Component组件 继承映射 对象模型(Java类结构) 继承映射 一个类继承体系一张表(subclass)(表结构) 继承映射 一个类继承体系一张表(subclass)(映射文件) class nameEmployee tableemployee discriminator-value0 id nameid generator classnative/ /id discriminator columntype typeint/ property namename/ many-to-one name”depart” column”depart_id”/ subclass nameSkiller discriminator-value1 property name”skill”/ /subclass subclass nameSales discriminator-value2 property namesell/ /subclass /class 一张表映射出一个继承树 操作就是一张表查询的效率高 缺点对于新增加某一个类型时就要修改表结构信息且有的字段必须可以为NULL 继承映射 每个子类一张表(joined-subclass) (表结构) 多态查询效率会很低要将所有的表来查询一遍 每个子类都存储为一张表 这是当每个子类的属性差别都很大时会用该种方式来处理 继承映射 每个子类一张表(joined-subclass) (映射文件) class nameEmployee tableemployee id nameid generator classnative/ /id property namename/ joined-subclass nameSkiller tableskiller key columnemployee_id/ property nameskill/ /joined-subclass joined-subclass nameSales tablesales key columnemployee_id/ property namesell/ /joined-subclass /class 继承映射 混合使用“一个类继承体系一张表”和“每个子类一张表” (表结构) 继承映射 混合使用“一个类继承体系一张表”和“每个子类一张表” (映射文件) class nameEmployee tableemployee id nameid generator classnative/ /id discriminator columntype/ property namename/ subclass nameSkiller property namenet/ /subclass subclass name”Sales” join tablesales key columnemployee_id/ property namesell/ /join /subclass /class 继承映射 每个具体类一张表(union-subclass) (表结构) 根据主键来查询 要求三张表的id都是不同的如果用这种结构来实现() 增删改都是直接对单表进行操作 进行查询时有可能对三张表来进行查询但hibernate会进行子查询连接查询 继承映射 每个具体类一张表(union-subclass) (映射文件) class nameEmployee abstracttrue id nameid generator classhilo/ /id property namename/ union-subclass nameSkiller tableskiller property nameskill/ /union-subclass union-subclass nameSales tablesales property namesell/ /union-subclass /class 主健不能是identity类型如果父类是abstract”true”就不会有表与之对应。 隐式多态映射文件没有联系限制比较多很少使用。 集合映射 集合映射(set, list, array,bag, map) set name”employees” key column”depart_id”/ one-to-many class”Employee”/ !-- element typestring columnname/ -- !-- composite-element class”YourClass” property name”prop1”/ property name”prop2”/ /composite -- /set 集合映射(set, list, array,bag, map) list name”employees” key column”depart_id”/ !—表中有单独的整型列表示list-index list-index column”order_column”/ one-to-many class”Employee”/ /list array name”employees” key column”depart_id”/ !—表中有单独的整型列表示list-index list-index column”order_column”/ one-to-many class”Employee”/ /array 集合映射(set, list, array,bag, map) bag nameemployees order-byid desc key column”depart_id”/ one-to-many class”Employee”/ /bag map nameemployees key column”depart_id”/ map-key typestring columnname/ one-to-many class”Employee”/ /map 集合映射(set, list, array,bag, map) 这些集合类都是Hibernate实现的类和JAVA中的集合类不完全一样set,list,map分别和JAVA中的Set,List,Map接口对应bag映射成JAVA的List这些集合的使用和JAVA集合中对应的接口基本一致在JAVA的实体类中集合只能定义成接口不能定义成具体类因为集合会在运行时被替换成Hibernate的实现。 集合的简单使用原则大部分情况下用set需要保证集合中的顺序用list想用java.util.List又不需要保证顺序用bag。 集合映射 cascade和inverse (Employee– Department) Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操作常用的cascade: none,all,save-update ,delete, lock,refresh,evict,replicate,persist, merge,delete-orphan(one-to-many)。一般对many-to-one,many-to-many不设置级联在one-to-one和one-to-many中设置级联。 inverse表“是否放弃维护关联关系”(在Java里两个对象产生关联时对数据库表的影响)在one-to-many和many-to-many的集合定义中使用inverse”true”表示该对象不维护关联关系该属性的值一般在使用有序集合时设置成false注意hibernate的缺省值是false。 one-to-many维护关联关系就是更新外键。many-to-many维护关联关系就是在中间表增减记录。 注:配置成one-to-one的对象不维护关联关系 懒加载 通过asm和cglib二个包实现Domain是非final的。 1.session.load懒加载。 2.one-to-one(元素)懒加载 必需同时满足下面三个条件时才能实现懒加载 (主表不能有constrainedtrue,所以主表没有懒加载) lazy!false 2)constrainedtrue 3)fetchselect 3.one-to-many (元素)懒加载1)lazy!false 2)fetchselect 4.many-to-one (元素)1)lazy!false 2)fetchselect 5.many-to-many (元素)1)lazy!false 2)fetchselect 6.能够懒加载的对象都是被改写过的代理对象当相关联的session没有关闭时访问这些懒加载对象代理对象的属性getId和getClass除外hibernate会初始化这些代理或用Hibernate.initialize(proxy)来初始化代理对象当相关联的session关闭后再访问懒加载的对象将出现异常。 初始时就创建了一个对象 如果你不需要那么它就不会去访问数据库 只有要真正需要数据时则需在session未关闭时去访问下数据库 对于一对一的情况下 主表的查询没有懒加载会从数据库中将从表查询出来 从表默认是不会加载而是返回代理形式会有懒加载的形式 对于一对多缺省是懒加载的如果不是就会当我们例如查询部门时会将所有的员工信息都查出来 对于getID() 和 getClass() 这都是不需要访问数据库的 不会初始化代理对象 对于相应映射关系时存在懒加载的机制 缓存 缓存的作用主要用来提高性能可以简单的理解成一个Map使用缓存涉及到三个操作把数据放入缓存、从缓存中获取数据、删除缓存中的无效数据。 一级缓存Session级共享。 save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中一级缓存不能控制缓存的数量所以要注意大批量操作数据时可能造成内存溢出可以用evict,clear方法清除缓存中的内容。 缓存 二级缓存SessionFactory级共享。 实现为可插拔通过修改cache.provider_class参数来改变; hibernate内置了对EhCache,OSCache,TreeCache,SwarmCache的支持可以通过实现CacheProvider和Cache接口来加入Hibernate不支持的缓存实现。 在hibernate.cfg.xml中加入: class-cache classclassName usageread-only/ 或在映射文件的class元素加入子元素: cache usageread-write/ 其中usage:read-only,read-write,nonstrict-read-write,transactional Session的:save(这个方法不适合native生成方式的主键), update,saveOrUpdate,list,iterator,get,load,以及Query,Criteria都会填充二级缓存但只有(没打开查询缓存时)Session的iterator,get,load会从二级缓存中取数据(iterator可能存在N1次查询)。 Query,Criteria(查询缓存)由于命中率较低所以hibernate缺省是关闭修改cache.use_query_cache为true打开对查询的缓存并且调用query.setCacheable(true)或criteria.setCacheable(true)。 SessionFactory中提供了evictXXX()方法用来清除缓存中的内容。 统计信息打开generate_statistics用sessionFactory.getSatistics()获取统计信息。 缓存 分布式缓存和中央缓存。 使用缓存的条件 1.读取大于修改。 2.数据量不能超过内存容量。 3.对数据要有独享的控制。 4.可以容忍出现无效数据。 事务 JDBCTransaction 单个数据库一个SesisonFactory对应一个数据库由JDBC实现。 Session session null; Transaction tx null; try { session sessionFactory.openSession(); tx session.beginTransaction(); //process tx.commit(); } catch(HibernateException e){ if(tx ! null)tx.rollback();throw e; }finally { if (session ! null)session.close(); } connection.setAutoCommit(false); connection.commit();conn.rollback(); JTATransaction 可以简单的理解成跨数据库的事物由应用JTA容器实现使用JTATransaction需要配置hibernate.transaction.factory_class参数该参数缺省值是org.hibernate.transaction. JDBCTransactionFactory当使用JTATransaction时需要将该参数改成org.hibernate.transaction.JTATransactionFactory并配置jta.UserTransaction参数JNDI名(Hibernate在启动JTATransaction时要用该值到JNDI的上下文Context中去找javax.transaction.UserTransaction)。 javax.transaction.UserTransactin tx context.lookup(“jndiName”); try{ tx.begin(); //多个数据库的session操作; //session1…. //session2…. tx.commit(); }catch(Exception e){ tx.rollback(); throw e; } session context和事务边界 用current_session_context_class属性来定义context用sessionFactory.getCurrentSession()来获得session其值为 1.threadThreadLocal来管理Session实现多个操作共享一个Session避免反复获取Session并控制事务边界此时session不能调用close当commit或rollback的时候session会自动关闭(connection.release_mode:after_transaction)。 Open session in view在生成渲染页面时保持 session打开。 2.jta由JTA事务管理器来管理事务(connection.release_mode:after_statement)。 悲观锁和乐观锁 悲观锁由数据库来实现乐观锁hibernate用version和timestamp来实现 事务边界 开启提交 回滚 如想在业务逻辑层控制事务 但业务逻辑层不会与数据访问层有相当大的耦合 Transaction因为是业务逻辑层的对象 悲观锁我读取到信息时会对信息进行加锁操作等数据修改完后对数据锁进行释放其他才能修改不可取 看数据库的版本号与提交的版本号哪个更加新如果数据库的新则不允许提交的 其他问题 hibernate.cfg.xml和hbm.xml内容解释 数据类型 1.property name“name” type“java.lang.String”/ type可以是hibernate、java类型或者你自己的类型(需要实现hibernate的一个接口)。 2.基本类型一般不需要在映射文件(hbm.xml)中说明只有在一个JAVA类型和多个数据库数据类型相对应时并且你想要的和hibernate缺省映射不一致时需要在映射文件中指明类型(如:java.util.Date,数据库DATE,TIME,DATATIME,TIMESTAMPhibernate缺省会把java.util.Date映射成DATATIME型而如果你想映射成TIME则你必须在映射文件中指定类型)。 3.数据类型的对应关系见参考文档5.2.2 Session是非线程安全的生命周期较短代表一个和数据库的连接在B/S系统中一般不会超过一个请求内部维护一级缓存和数据库连接如果session长时间打开会长时间占用内存和数据库连接。 SessionFactory是线程安全的一个数据库对应一个SessionFactory生命周期长一般在整个系统生命周期内有效SessionFactory保存着和数据库连接的相关信息userpasswordurl和映射信息以及Hibernate运行时要用到的一些信息。 session内部封装了connection连接 对于session尽量晚的获得尽量早的释放 对于主键为自动增长类型因为要从数据库中获取才能进行插入所以会直接进入数据库 而不像其他类型先进入缓存等提交时才与数据库交互 其他问题 flush时将一级缓存与数据库同步 大批处理 大量操作数据时可能造成内存溢出解决办法如下 1.清除session中的数据 for(int i0;i100000;i)session.save(obj); for(int i0;i100000;i){ session.save(obj); if(i% 50 0){session.flush(); session.clear();} } 2.用StatelessSession接口它不和一级缓存、二级缓存交互也不触发任何事件、监听器、拦截器通过该接口的操作会立刻发送给数据库与JDBC的功能一样。 StatelessSession s sessionFactory.openStatelessSession();该接口的方法与Session类似。 3.Query.executeUpdate()执行批量更新会清除相关联的类二级缓存(sessionFactory.evict(class))也可能会造成级联和乐观锁定出现问题 其他问题 HQL 1查询多个对象select art, user from Article art, User user where art.author.iduser.id and art.id:id这种方式返回的是Object[]Object[0]:article,Object[1]:user。 2分页query.setFirstResult,query.setMaxResults. 查询记录总数query.iterate(“select count(*) from Person”).next() 3批量更新query.executeUpdate()可能造成二级缓存有实效数据。 Criteria 1排序Criteria.addOrder(Order.desc(propertyName)); 2关联查询criteria.setFetchMode(“propertyName”, FetchMode.SELECT)与映射文件中关联关系的fetch作用一致。 3投影Projections.rowCount(),max(propertyName), avg, groupProperty… 4分页Projections.rowCount(),criteria.setFirstResult(),criteria.setMaxResults() 5DetachedCriteria可在session外创建在其他层创建比如在Service中创建然后用getExecutableCriteria(session)方法创建Criteria对象来完成查询。 6Example查询,Example.create(obj);criteria.add(example)。 查询表达式是不会利用缓存来进行查询的默认情况下 离线查询实现动态查询DetachedCriteria 他构造时不需要session 而Cruteria构造时需要 其他问题 N1次查询和懒加载 1.用Query.iterator可能会有N1次查询。 2.懒加载时获取关联对象。 3.如果打开对查询的缓存即使用list也可能有N1次查询。 拦截器与事件 拦截器与事件都是hibernate的扩展机制Interceptor接口是老的实现机制现在改成事件监听机制他们都是hibernate的回调接口hibernate在save,delete,update…等会回调这些类。 SQL和命名查询 用Map代替Domain对象将对象转化为XML。 命名查询是将查询语句集中起来到配置文件中更方便的修改 Hibernate不适合的场景 不适合OLAP(On-Line Analytical Processing联机分析处理)以查询分析数据为主的系统适合OLTPon-line transaction processing联机事务处理。 对于些关系模型设计不合理的老系统也不能发挥hibernate优势。 数据量巨大性能要求苛刻的系统hibernate也很难达到要求,批量操作数据的效率也不高。 与JPA的集成(annotation方式) 需要添加的包ejb3-persistence.jar, hibernate-entitymanager.jar, hibernate-annotations.jar, hibernate-commons-annotations.jar, jboss-archive-browsing.jar, javassist.jar 配置文件%CLASSPATH%/META-INF/persistence.xml JAVA代码 EntityManagerFactory emf Persistence.createEntityManagerFactory(name); //(Name:在persistence.xml中指定。) EntityManager em emf.createEntityManager(); EntityTransaction tx em.getTransaction(); Tx.begin(); Em.persist(entity);//remove,merge,find Tx.commit(); Em.close(); Emf.close(); 最佳实践 见hibernate参考文档 转载于:https://www.cnblogs.com/james1207/p/3323080.html