hibernate高级应用
来源:互联网 发布:夏日大作战 知乎 编辑:程序博客网 时间:2024/05/30 04:48
DML风格的批量更新和删除
语法格式:
delete | update from? [Where condition]
from是可选的,可以不写。from字句后面只能有一个类名。可以指定别名。
可以使用where字句查询但不能使用连接。
String hqlUpdate = "update User u set name=:newName";int updateEntities = session.creaateQuery(hqlUpdate).setString("newName","新名字").executeUpdate();String hqlDelete = "delete User";int deleteEntities = session.createQuery(hqlDelete).executeUpdate();
HQL查询
- 获取session对象
- 编写HQL语句
- session.createQuery(hql)创建查询对象
- 调用Query.setXXX方法设置查询参数
- 调用Query对象的list()或uniqueResult()返回查询结果。
List p1 = session.createeQuery("select distinct p from Person p join p.myEvents where title = :eventTitle") .setString("eventTitle","很普通") .list();List p2 = session.createeQuery("select distinct p from Person p inner join p.myEvents events where event.happenDate between :firstDate and :endDate") .setDate("firstDate",new Date()) .setDate("lastDate",new Date()) .list();
条件查询
- Creteria:代表依次查询
- Criterion:代表一个查询条件
- Restrictions:产生查询条件的工具类。
执行条件查询的步骤:- 获得session
- session创建criteria对象。
- 使用Restrictions的静态方法创建Criterion对象。
- 向Criteria对象添加Criterion查询条件。
5 执行Criteria的list()或uniqueResult()。
List list = session.createCriteria(Student.class) .add(Restrictions.gt("name","a")) .list():
Cretiria还有如下方法:
setFirstResult(int);
setMaxResult(int);
addOrder(Order order)
分组、投影、聚合
使用Projection代表投影运算。Projection是一个接口,而Projections作为Projection的 工厂。负责生产Projection对象。
List cats = session.createCriteria(Cat.class) .setProjection(Projections.projectionList() .add(Projection.rowCOunt()) .add(Projection.avg("weight")) .add(Projection.groupProperty("color")) .addOrder(Order.asc("color")) ) .list();
离线查询和子查询
使用DetachedCriteria实现。
//离线查询DetachedCriteria query = DetachedCriteria .forClass(Student.class) .setProjection(Property.forName("name")); Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); List list = query.getExecutableCriteria(session) .list();//子查询List list = session.createCriteria(Student.class) //下面两种方式都行 .add( Property.forName("name").in(query))// .add( Subqueries.propertyIn("name" , query)) .list();
SQL查询
通过Query的子接口SQLQuery.它多了两个方法:
addEntity():将查询到的记录与特定的实体相关联。
addScalar():将查询到的记录关联成标量值。
//明确指定查询中返回的数据列返回的类型session.createSQLQeury("select * from student_inf") .addScalar("name",StandardBasicTypes.STRING) .list();//实体查询String sql = "select * from enroment_inf where year=?1";List list = session.createSQLQuery(sql) .addEntity(Enrolment.class) .setInteger("1",2005) .list();//映射多个实体String sqlString = "select s.*,e.*,c.* " + "from student_inf s,enrolment_inf e,course_inf c " + "where s.student_id = e.student_id " + "and e.course_code = c.course_code"; List list = session.createSQLQuery(sqlString) .addEntity("s", Student.class) .addEntity("e", Enrolment.class) .addEntity("c", Course.class) .list();for (Object ele : list) { Object[] objs = (Object[])ele; Student s = (Student)objs[0]; Enrolment e = (Enrolment)objs[1]; Course c = (Course)objs[2]; System.out.println(s.getName() + "\t" + e.getYear() + "\t" + e.getSemester() + "\t" + c.getName()); }
还可将查询结果转换成非持久化类。(javabean).Query接口有个setResultTransformer()方法。传进一个Transformers对象即可转换。
String sqlString = "select s.name stuName, c.name courseName " + "from student_inf s,enrolment_inf e,course_inf c " + "where s.student_id = e.student_id " + "and e.course_code = c.course_code "; List list = session.createSQLQuery(sqlString) .setResultTransformer(Transformers .aliasToBean(StudentCourse.class)) .list();//StudnetCourse只有两个属性stuName,courseName。
处理关联和映射
将关联实体转换成查询结果
SQLQuery.addJoin(String alias,String property):第一个是转换后的实体名,第二个是待转换的实体属性。
String sqlString = "select s.* , e.* from student_inf s , " + "enrolment_inf e where s.student_id=e.student_id"; List list = session.createSQLQuery(sqlString) .addEntity("s", Student.class) .addJoin("e" , "s.enrolments") .list(); for (Object ele : list) { Object[] objs = (Object[])ele; Student s = (Student)objs[0]; Enrolment e = (Enrolment)objs[1]; System.out.println(s.getName() + "\t" + e.getYear()); }
命名sql查询
可以使用@NamedNativeQuery来定义原生sql查询。有如下属性:
name:查询名称
query:sql语句
resultClass:查询映射的实体类的类名
resultSetMapping:指定一个sql结果映射
如果需要使用resultresultSetMapping属性。则需要使用@SqlResultSetMapping定义sql结果映射。
将查询得到的结果转换为标量查询或实体查询。
@SqlResultSetMapping有以下属性:
name:
columns:值为@ColumnResult注解数组。每个@ColumnResult定义一个标量查询。
entities:值为@EntityResult注解数组。每个@EntityResult定义一个实体查询
classes:值为@ConstructorResult注解数组。每个@ConstructorResult负责将指定的多列转换为javabean的对应属性。
@NamedNativeQueries({@NamedNativeQuery(name="simpleQuery" , query="select s.student_id , s.name from student_inf s" , resultClass=Student.class),@NamedNativeQuery(name="queryTest" , query="select s.*,e.*,c.* from student_inf s,enrolment_inf e," + " course_inf c where s.student_id = e.student_id and" + " e.course_code = c.course_code and e.year=:targetYear" , resultSetMapping = "firstMapping"),@NamedNativeQuery(name="callProcedure" , query="{call select_all_student()}" , resultSetMapping = "secondMapping")})@SqlResultSetMappings({@SqlResultSetMapping(name="firstMapping" , entities={@EntityResult(entityClass=Student.class), @EntityResult(entityClass=Enrolment.class), @EntityResult(entityClass=Course.class , fields= { @FieldResult(name="courseCode" , column="c.course_code"), @FieldResult(name="name" , column="c.name") }) } , columns={@ColumnResult(name="s.name" , type=String.class)}),@SqlResultSetMapping(name="secondMapping" , entities={@EntityResult(entityClass=Student.class , fields= { @FieldResult(name="studentNumber" , column="student_id"), @FieldResult(name="name" , column="name") }) })})//调用List list = session.getNamedQuery("queryTest") .setInteger("targetYear" , 2005) .list();for(Object ele : list) { Object[] objs = (Object[])ele; Student s = (Student)objs[0]; Enrolment e = (Enrolment)objs[1]; Course c = (Course)objs[2]; String stuName = (String)objs[3]; System.out.println(s.getName() + "\t" + e.getYear() + "\t" + e.getSemester() + "\t=" + e.getCourse().getName() + "=\t" + stuName); }
调用存储过程
可以通过命名sql查询来调用存储过程或函数。对于函数,该函数必须返回一个结果集。对于存储过程,该存储过程的第一个参数必须是参数,且其数据类型必须是结果集。
//创建一个简单的存储过程create procedure select_all_student()select * from student_inf;//定义一个调用存储过程的命名sql@NameNativeQuery(name="callProcedure" ,query="{call select_all_student()}" ,resultSetMapping="secondMapping")@SqlResultSetMapping(name="secondMapping" ,entities={@EntityResult(entityClass=Student.class,fileds= { @FieldResult(name="studentNumber",column="student_id"), @FieldResult(name="name",column="name") }) })//调用存储过程List list = session.getNamedQuery("callProcedure") .list();
使用定制sql
不使用hibernate提供的默认sql语句来执行。而使用自己写的。
如果想要调用存储过程来执行删除,更新等操作。则需指定callable=true.
@SQLInsert(callable=true,sql="{call createPerson(?,?)}")@SQLUpdate(callable=true,sql="{? = call UpdatePerson(?)}")@SQLDelete(callable=true,sql="{? = call deletePerson(?,?)}")
还可用命名sql实现定制装载。例如在装载News时为title属性的前后增加三个等号。
@SQLInsert(sql="insert into news_inf(content , title) values(upper(?), ?)")@SQLUpdate(sql="update news_inf set content=upper(?), title=? where news_id=?")@SQLDelete(sql="delete from news_inf where news_id=?")@SQLDeleteAll(sql="delete from news_inf")@Loader(namedQuery = "news_loader")@NamedNativeQuery(name="news_loader" , query="select news_id , concat('===' , concat(title , '===')) as title" + " , content from news_inf n where news_id=?" , resultClass = News.class)@Entity@Table(name="news_inf")public class News{ @Id @Column(name="news_id") @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String title; private String content;
数据过滤
过滤器与持久化类的@Where注解非常相似。他们的区别是过滤器可以带参数,运用程序可以在运行时决定是否启动指定的过滤器。使用怎样的参数值。而@Where注解将一直生效。且无法动态传入参数。
使用过滤器的三个步骤:
1. 定义过滤器,使用hibernate提供的@FilterDef注解定义过滤器。如果需要定义多个过滤器则需要使用@FilterDefs注解组合多个@FilterDef.
2. 使用@Filter元素应用过滤器
3. 在代码中通过session启用过过滤器。
@FilterDef属性:
name:
defaultCondition:默认过滤条件。可不写。
parameters:指定过滤器中sql表达式支持的参数。
@FilterDefs({@FilterDef(name="effectiveDate" , parameters={@ParamDef(name="asOfDate" , type="date")}),@FilterDef(name="category" , parameters={@ParamDef(name="catId" , type="int")})})@Entity@Table(name="product_inf")@Filter(name="effectiveDate" , condition=":asOfDate BETWEEN eff_start_date AND eff_end_date")public class Product{ @Id @Column(name="product_id") @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; @Column(name="product_name") private String name; @Column(name="stock_number") private int stockNumber; @Column(name="eff_start_date") private Date effectiveStartDate; @Column(name="eff_end_date") private Date effectiveEndDate; @ManyToMany(targetEntity=Category.class) @JoinTable(name="product_category" , joinColumns=@JoinColumn(name="product_id") , inverseJoinColumns=@JoinColumn(name="category_id")) @Filters({ @Filter(name="effectiveDate" , condition=":asOfDate BETWEEN eff_start_date and eff_end_date"), @Filter(name="category" , condition="category_id = :catId") }) private Set<Category> categories = new HashSet<>();
系统默认不启动过滤器,必须通过session.enableFilteer(String filterName)才可以启用,而且一旦启动他将在整个session内有效。知道session调用disableFilter()方法。
session.enableFilter("effectiveDate") .setParameter("asOfDate", new Date()); session.enableFilter("category") .setParameter("catId", 2); List list = session.createQuery("from Product as p").list(); for (Object obj : list) { Product p = (Product)obj; System.out.println(p.getName()); System.out.println("----" + p.getCategories()); }
拦截器
通过Interceptor接口,可以从session中回调应用程序的特定方法。这种回调机制可以让应用程序在持久化对象被保存、删除、修改、加载之前,检查并修改其属性。
使用步骤:
1. 定义实现Interceptor接口的拦截器。最好继承EmptyInterceptor类。
public class MyInterceptor extends EmptyInterceptor{ private int updates; private int creates; public void onDelete(Object entity , Serializable id , Object[] state , String[] propertyNames , Type[] types) { // do nothing } public boolean onFlushDirty(Object entity , Serializable id , Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { updates++; for ( int i = 0; i < propertyNames.length; i++ ) { if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) { currentState[i] = new Date(); return true; } } return false; } public boolean onLoad(Object entity , Serializable id , Object[] state,String[] propertyNames,Type[] types) { for ( int i = 0; i < propertyNames.length ; i++ ) { if ( "name".equals( propertyNames[i] ) ) { System.out.println( state[i] ); return true; } } return false; } public boolean onSave(Object entity , Serializable id , Object[] state,String[] propertyNames,Type[] types) { creates++; for ( int i = 0; i < propertyNames.length; i++ ) { if ("createTimestamp".equals( propertyNames[i])) { state[i] = new Date(); return true; } } return false; } public void postFlush(Iterator entities) { System.out.println("´创建的次数" + creates + ", 更新的次数" + updates); } public void preFlush(Iterator entities) { // do nothing } public void beforeTransactionCompletion(Transaction tx) { System.out.println("事务即将开始"); } public void afterTransactionCompletion(Transaction tx) { System.out.println("事务已将结束"); }
- 通过sessionFactory.openSession(Interceptor in)启动局部拦截器。或Configuration.setInterceptor(Interceptor in)来设置全局拦截器。
static Configuration cfg = new Configuration() .configure() .setInterceptor(new MyInterceptor());
事件系统
可作为拦截器的补充或代替拦截器。
Session接口的每个方法都有对应的事件。比如LoadEvent,FlushEvent等。当session调用某个方法时,session会生成对应的事件。并激活对应的事件监听器。
可以在系统中实现并注册LoadEventListener监听器,负责所有的调用session.load()方法的请求。
使用事件系统的步骤:
1. 实现自己的事件监听器类。一般采用继承系统默认的监听器,扩展特定的方法。
2. 注册自定义事件监听器,代替系统默认的事件监听器。
public class MySaveListener extends DefaultSaveEventListener{ public Serializable performSaveOrUpdate(SaveOrUpdateEvent event) { System.out.println(event.getObject()); return super.performSaveOrUpdate(event); }}public class MyLoadListener extends DefaultLoadEventListener{ public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException { System.out.println(event.getEntityClassName() + "==========" + event.getEntityId()); super.onLoad(event, loadType); }}
hibernate提供了一个EventListenerRegistry接口来注册事件监听器。一共有三个方法:
appendListener();加到系统默认的事件监听器后面
prependListener():加到系统默认的事件监听器前面
setListener():替换系统默认的事件监听器
static ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(cfg.getProperties()).build(); static SessionFactory sf = cfg.buildSessionFactory(serviceRegistry); static{ EventListenerRegistry elr = ((SessionFactoryImpl)sf) .getServiceRegistry().getService(EventListenerRegistry.class); elr.setListeners(EventType.SAVE, MySaveListener.class); elr.setListeners(EventType.LOAD, MyLoadListener.class); }
- 14、Hibernate高级应用
- hibernate高级应用
- Hibernate事务的高级应用
- Hibernate 3.x过滤器的高级应用
- Hibernate高级应用:性能优化策略
- Hibernate高级
- 高级应用
- hibernate高级特性_1
- Hibernate QBC高级查询
- Hibernate高级查询方法
- Hibernate QBC高级查询
- Hibernate高级查询实战
- Hibernate高级查询实战
- Hibernate高级查询方法
- Hibernate高级查询方法
- Hibernate QBC高级查询
- Hibernate高级查询实战
- Hibernate QBC高级查询 .
- Codeforces_714E:Sonya_and_Problem_Wihtout_a_Legend(DP+想法题)
- codeforces-754A-Lesha and array splitting(简单分类处理)
- 【数据结构】高效双向链表list、树tree(二叉树)
- 九度 oj 题目1086:最小花费
- c++ STL Algorithm简单总结备忘
- hibernate高级应用
- Maven 的安装以及Eclispe集成
- poj2503 哈希
- javap使用
- 图论(二)树
- 关于map处理String的复杂度问题
- JDBC重要知识点
- Linux history显示时间戳
- 蓝桥杯——迭代法进阶 几个实际应用问题(2017.1.14)