Ibatis SqlExecutor.executeQuery

Posted on

Ibatis SqlExecutor.executeQuery

小猫的窝棚

#

Ibatis SqlExecutor.executeQuery(ZZ)")

分类: Java 2008-07-28 10:37 688人阅读 评论(1) 收藏 举报

一直以来ibatis的分页都是通过滚动ResultSet实现的,应该算是逻辑分页吧。逻辑分页虽然能很干净地独立于特定数据库,但效率在多数情况下不及特定数据库支持的物理分页,而hibernate的分页则是直接组装sql,充分利用了特定数据库的分页机制,效率相对较高。本文讲述的就是如何在不重新编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。 基本思路就是找到ibatis执行sql的地方,截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是com.ibatis.sqlmap.engine.execution.SqlExecutor,此类没有实现任何接口,这多少有点遗憾,因为接口是相对稳定契约,非大的版本更新,接口一般是不会变的,而类就相对易变一些,所以这里的代码只能保证对当前版本(2.1.7)的ibatis有效。下面是SqlExecutor执行查询的方法: /// / Long form of the method to execute a query / / @param request - the request scope / @param conn - the database connection / @param sql - the SQL statement to execute / @param parameters - the parameters for the statement / @param skipResults - the number of results to skip / @param maxResults - the maximum number of results to return / @param callback - the row handler for the query / / @throws SQLException - if the query fails // public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { ErrorContext errorContext = request.getErrorContext(); errorContext.setActivity("executing query"); errorContext.setObjectId(sql); PreparedStatement ps = null; ResultSet rs = null; try { errorContext.setMoreInfo("Check the SQL Statement (preparation failed)."); Integer rsType = request.getStatement().getResultSetType(); if (rsType != null) { ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY); } else { ps = conn.prepareStatement(sql); } Integer fetchSize = request.getStatement().getFetchSize(); if (fetchSize != null) { ps.setFetchSize(fetchSize.intValue()); } errorContext.setMoreInfo("Check the parameters (set parameters failed)."); request.getParameterMap().setParameters(request, ps, parameters); errorContext.setMoreInfo("Check the statement (query failed)."); ps.execute(); rs = getFirstResultSet(ps); if (rs != null) { errorContext.setMoreInfo("Check the results (failed to retrieve results)."); handleResults(request, rs, skipResults, maxResults, callback); } // clear out remaining results while (ps.getMoreResults()); } finally { try { closeResultSet(rs); } finally { closeStatement(ps); } } } 其中handleResults(request, rs, skipResults, maxResults, callback)一句用于处理分页,其实此时查询已经执行完毕,可以不必关心handleResults方法,但为清楚起见,下面来看看handleResults的实现: private void handleResults(RequestScope request, ResultSet rs, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { try { request.setResultSet(rs); ResultMap resultMap = request.getResultMap(); if (resultMap != null) { // Skip Results if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (skipResults > 0) { rs.absolute(skipResults); } } else { for (int i = 0; i < skipResults; i++) { if (!rs.next()) { break; } } } // Get Results int resultsFetched = 0; while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) { Object[] columnValues = resultMap.resolveSubMap(request, rs).getResults(request, rs); callback.handleResultObject(request, columnValues, rs); resultsFetched++; } } } finally { request.setResultSet(null); } } 此处优先使用的是ResultSet的absolute方法定位记录,是否支持absolute取决于具体数据库驱动,但一般当前版本的数据库都支持该方法,如果不支持则逐条跳过前面的记录。由此可以看出如果数据库支持absolute,则ibatis内置的分页策略与特定数据库的物理分页效率差距就在于物理分页查询与不分页查询在数据库中的执行效率的差距了。因为查询执行后读取数据前数据库并未把结果全部返回到内存,所以本身在存储占用上应该差距不大,如果都使用索引,估计执行速度也差不太多。 继续我们的话题。其实只要在executeQuery执行前组装sql,然后将其传给executeQuery,并告诉handleResults我们不需要逻辑分页即可。拦截executeQuery可以采用aop动态实现,也可直接继承SqlExecutor覆盖executeQuery来静态地实现,相比之下后者要简单许多,而且由于SqlExecutor没有实现任何接口,比较易变,动态拦截反到增加了维护的工作量,所以我们下面来覆盖executeQuery: package com.aladdin.dao.ibatis.ext; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.aladdin.dao.dialect.Dialect; import com.ibatis.sqlmap.engine.execution.SqlExecutor; import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback; import com.ibatis.sqlmap.engine.scope.RequestScope; public class LimitSqlExecutor extends SqlExecutor { private static final Log logger = LogFactory.getLog(LimitSqlExecutor.class); private Dialect dialect; private boolean enableLimit = true; public Dialect getDialect() { return dialect; } public void setDialect(Dialect dialect) { this.dialect = dialect; } public boolean isEnableLimit() { return enableLimit; } public void setEnableLimit(boolean enableLimit) { this.enableLimit = enableLimit; } @Override public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS) && supportsLimit()) { sql = dialect.getLimitString(sql, skipResults, maxResults); if(logger.isDebugEnabled()){ logger.debug(sql); } skipResults = NO_SKIPPED_RESULTS; maxResults = NO_MAXIMUM_RESULTS; } super.executeQuery(request, conn, sql, parameters, skipResults, maxResults, callback); } public boolean supportsLimit() { if (enableLimit && dialect != null) { return dialect.supportsLimit(); } return false; } } 其中: skipResults = NO_SKIPPED_RESULTS; maxResults = NO_MAXIMUM_RESULTS; 告诉handleResults不分页(我们组装的sql已经使查询结果是分页后的结果了),此处引入了类似hibenate中的数据库方言接口Dialect,其代码如下: package com.aladdin.dao.dialect; public interface Dialect { public boolean supportsLimit(); public String getLimitString(String sql, boolean hasOffset); public String getLimitString(String sql, int offset, int limit); } 下面为Dialect接口的MySQL实现: package com.aladdin.dao.dialect; public class MySQLDialect implements Dialect { protected static final String SQL_END_DELIMITER = ";"; public String getLimitString(String sql, boolean hasOffset) { return new StringBuffer(sql.length() + 20).append(trim(sql)).append( hasOffset ? " limit ?,?" : " limit ?") .append(SQL_END_DELIMITER).toString(); } public String getLimitString(String sql, int offset, int limit) { sql = trim(sql); StringBuffer sb = new StringBuffer(sql.length() + 20); sb.append(sql); if (offset > 0) { sb.append(" limit ").append(offset).append(',').append(limit) .append(SQL_END_DELIMITER); } else { sb.append(" limit ").append(limit).append(SQL_END_DELIMITER); } return sb.toString(); } public boolean supportsLimit() { return true; } private String trim(String sql) { sql = sql.trim(); if (sql.endsWith(SQL_END_DELIMITER)) { sql = sql.substring(0, sql.length() - 1 - SQL_END_DELIMITER.length()); } return sql; } } 接下来的工作就是把LimitSqlExecutor注入ibatis中。我们是通过spring来使用ibatis的,所以在我们的dao基类中执行注入,代码如下: package com.aladdin.dao.ibatis; import java.io.Serializable; import java.util.List; import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport; import com.aladdin.dao.ibatis.ext.LimitSqlExecutor; import com.aladdin.domain.BaseObject; import com.aladdin.util.ReflectUtil; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.engine.execution.SqlExecutor; import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient; public abstract class BaseDaoiBatis extends SqlMapClientDaoSupport { private SqlExecutor sqlExecutor; public SqlExecutor getSqlExecutor() { return sqlExecutor; } public void setSqlExecutor(SqlExecutor sqlExecutor) { this.sqlExecutor = sqlExecutor; } public void setEnableLimit(boolean enableLimit) { if (sqlExecutor instanceof LimitSqlExecutor) { ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit); } } public void initialize() throws Exception { if (sqlExecutor != null) { SqlMapClient sqlMapClient = getSqlMapClientTemplate() .getSqlMapClient(); if (sqlMapClient instanceof ExtendedSqlMapClient) { ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient) .getDelegate(), "sqlExecutor", SqlExecutor.class, sqlExecutor); } } } ... } 其中的initialize方法执行注入,稍后会看到此方法在spring Beans 配置中指定为init-method。由于sqlExecutor是com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient的私有成员,且没有公开的set方法,所以此处通过反射绕过java的访问控制,下面是ReflectUtil的实现代码: package com.aladdin.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ReflectUtil { private static final Log logger = LogFactory.getLog(ReflectUtil.class); public static void setFieldValue(Object target, String fname, Class ftype, Object fvalue) { if (target == null || fname == null || "".equals(fname) || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) { return; } Class clazz = target.getClass(); try { Method method = clazz.getDeclaredMethod("set" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1), ftype); if (!Modifier.isPublic(method.getModifiers())) { method.setAccessible(true); } method.invoke(target, fvalue); } catch (Exception me) { if (logger.isDebugEnabled()) { logger.debug(me); } try { Field field = clazz.getDeclaredField(fname); if (!Modifier.isPublic(field.getModifiers())) { field.setAccessible(true); } field.set(target, fvalue); } catch (Exception fe) { if (logger.isDebugEnabled()) { logger.debug(fe); } } } } }

到此剩下的就是通过Spring将sqlExecutor注入BaseDaoiBatis中了,下面是Spring Beans配置文件: <?xml version="1.0" encoding="UTF-8"?> classpath:/com/aladdin/dao/ibatis/sql-map-config.xml

此后就可以通过调用org.springframework.orm.ibatis.SqlMapClientTemplate的 public List queryForList(final String statementName, final Object parameterObject, final int skipResults, final int maxResults) throws DataAccessException 或 public PaginatedList queryForPaginatedList(final String statementName, final Object parameterObject, final int pageSize) throws DataAccessException 得到分页结果了。建议使用第一个方法,第二个方法返回的是PaginatedList,虽然使用简单,但是其获得指定页的数据是跨过我们的dao直接访问ibatis的,不方便统一管理。

/* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

个人资料

fulianglove

  • 访问:19467次
  • 积分:496分
  • 排名:第13741名

  • 原创:22篇

  • 转载:32篇
  • 译文:0篇
  • 评论:24条

文章搜索

文章分类

文章存档

评论排行

.NET

java技术链接

Hibernate的体系结构与分析、工作原理

Posted on

Hibernate的体系结构与分析、工作原理

本文摘自 李刚 著 《Java EE企业应用实战》

    现在我们知道了一个概念**Hibernate Session**,只有处于**Session**管理下的**POJO**才具有持久化操作能力。当应用程序对于处于**Session**管理下的**POJO**实例执行操作时,**Hibernate**将这种面向对象的操作转换成了持久化操作能力。

HIbernate简要的体系结构如下图所示:

    通过上图能够发现HIbernate需要一个**hibernate.properties**文件,该文件用于配置**Hibernate**和数据库连接的信息。还需要一个XML文件,该映射文件确定了持久化类和数据表、数据列之间的想对应关系。

除了使用hibernate.properties文件,还可以采用另一种形式的配置文件: /*.cfg.xml文件。在实际应用中,采用XML配置文件的方式更加广泛,两种配置文件的实质是一样的。

    Hibernate的持久化解决方案将用户从赤裸裸的JDBC访问中释放出来,用户无需关注底层的JDBC操作,而是以面向对象的方式进行持久层操作。底层数据连接的获得、数据访问的实现、事务控制都无需用户关心。这是一种“全面解决”的体系结构方案,将应用层从底层的JDBC/JTA API中抽象出来。通过配置文件来管理底层的JDBC连接,让Hibernate解决持久化访问的实现。这种“全面解决”方案的体系结构图如图所示:

    针对以上的Hibernate全面解决方案架构图:

  (1)**SessionFactory**:**这是Hibernate的关键对象,**它是单个数据库映射关系经过编译后的内存镜像,它也是**线程安全的**。**它是生成Session的工厂**,本身要应用到ConnectionProvider,该对象可以在进程和集群的级别上,为那些事务之间可以重用的数据提供可选的二级缓存。

  (2)**Session**:它是应用程序和持久存储层之间交互操作的一个单线程对象。它也是Hibernate持久化操作的关键对象,所有的持久化对象必须在Session的管理下才能够进行持久化操作。**此对象的生存周期很短,其隐藏了JDBC连接,也是Transaction 的工厂。Session对象有一个一级缓存,现实执行Flush之前,所有的持久化操作的数据都在缓存中Session对象处。**

  (3)**持久化对象**:系统创建的POJO实例一旦与特定Session关联,并对应数据表的指定记录,那该对象就处于持久化状态,这一系列的对象都被称为持久化对象。程序中对持久化对象的修改,都将自动转换为持久层的修改。**持久化对象完全可以是普通的Java Beans/POJO,唯一的特殊性是它们正与Session关联着。**

  (4)**瞬态对象和脱管对象**:系统进行new关键字进行创建的Java 实例,没有Session 相关联,此时处于瞬态。瞬态实例可能是在被应用程序实例化后,尚未进行持久化的对象。如果一个曾今持久化过的实例,但因为Session的关闭而转换为脱管状态。

  (5)**事务(Transaction)**:代表一次原子操作,它具有数据库事务的概念。但它通过抽象,将应用程序从底层的具体的JDBC、JTA和CORBA事务中隔离开。在某些情况下,一个Session 之内可能包含多个Transaction对象。虽然事务操作是可选的,但是所有的持久化操作都应该在事务管理下进行,即使是只读操作。

  (6)**连接提供者(ConnectionProvider):****它是生成JDBC的连接的工厂,同时具备连接池的作用。他通过抽象将底层的DataSource和DriverManager隔离开。这个对象无需应用程序直接访问,仅在应用程序需要扩展时使用。**

  (7)事务工厂(TransactionFactory):他是生成Transaction对象实例的工厂。该对象也无需应用程序的直接访问。

来源: [http://blog.csdn.net/titilover/article/details/6920457](http://blog.csdn.net/titilover/article/details/6920457)

前面说了一些宏观上学习框架相关的思想方面的东西,下面继续来介绍我经常使用的框架和框架的分析,这篇博客主要介绍的是hibernate框架。

  首先说hibernate框架是数据持久层的框架,这个框架是非常强大的,它让编程人员纯粹的用面向对象的方式来做开发,让编程人员所面对的都是对象。仅仅从这一点它的设计思路就是非常让编程人员喜爱的。

  回想我们普通的开发流程,和客户沟通定需求,抽象出来原型,从原型中建立数据模型到库表结构的建立,之后在映射成对象模型,之后在用oo的设计思想完成后续的程序开发。但是当我们使用了hibernate框架以后,原先的设计思路就显得不再那么具有优势了。我们直接建立对象模型,之后利用hibernate框架映射成数据模型,我们不再去考虑数据库关系模型的东西,仅仅考虑的东西仅仅就是类和对象,这样的开发才是面向对象的开发,也才是最接近人类思考问题的方式。所以hibernate框架的设计思路是非常好的。

    hibernate框架设计思路的优越性其实体现在了它本身的框架的原理上。hibernate封装了JDBC,减轻了开发人员在持久层的大量重复性工作,它利用了java反射机制来实现程序的透明性;它就是通过这两点才达到从对象出发而非关系数据库出发的效果。



  介绍这么多理论性的东西之后我们能够感觉到hibernate框架的强大,来看看它的结构图:

   在hibernate框架中有几个比较重要的接口和类:
  1. Query接口:Query负责执行各种数据库查询。它可以使用HQL语句或SQL语句两种表达方式。

  2. Configuration类:Configuration类负责配置并启动Hibernate,创建SessionFactory对象

  3. SessionFactory接口:SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象

  4. Session接口:Session接口负责执行被持久化对象的CRUD操作

  5. Transaction接口:Transaction接口负责事务相关的操作

     hibernate框架就是在利用这几个接口来封装了JDBC,而且我们用这些接口来操作数据库变得非常简单,减少了我们在持久层的代码量。

   从这个结构图和我的一些分析就能发现hibernate框架是非常强大,而且它给我们开发人员的开发带来了非常大的便利,尤其是他的设计思路还有它的“全自动”的映射对象模型和关系模型。

   但是hibernate框架也有它的一些缺点:
  1. 既然是封装了JDBC,所以很明显它没有JDBC的效率高,尤其是在大量的处理表更新操作的时候。

  2. 它有局限性,一个持久化类不能映射多个表

  3. 它应对大数量的时候显得非常笨拙,这一点没有JDBC和接下来要介绍的IBatis框架
   其实一项技术或者一个框架都有它的优缺点,选择最合适的才是王道。

来源: [http://blog.csdn.net/lfsf802/article/details/7941958](http://blog.csdn.net/lfsf802/article/details/7941958)

Hibernate工作原理:

1.Hibernate 的初始化.

读取Hibernate 的配置信息-〉创建Session Factory

1)创建Configeration类的实例:

它的构造方法:将配置信息(Hibernate config.xml)读入到内存。 一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。

2)创建SessionFactory实例:

把Configeration 对象中的所有配置信息拷贝到SessionFactory的缓存中。 SessionFactory的实例代表一个数据库存储员源,创建后不再与Configeration 对象关联。

3)调用SessionFactory创建Session的方法:

    1】用户自行提供JDBC连接。

    Connection con=dataSource.getConnection();
    Session s=sessionFactory.openSession(con);

    2】让SessionFactory提供连接

    Session s=sessionFactory.openSession();

4)通过Session 接口提供的各种方法来操纵数据库访问。

Hibernate 的缓存体系

一级缓存:

Session 有一个内置的缓存,其中存放了被当前工作单元加载的对象。 每个Session 都有自己独立的缓存,且只能被当前工作单元访问。

二级缓存:

SessionFactory的外置的可插拔的缓存插件。其中的数据可被多个Session共享访问。

SessionFactory的内置缓存:存放了映射元数据,预定义的Sql语句。

Hibernate 中Java对象的状态

1.临时状态 (transient)

特征:

1】不处于Session 缓存中 2】数据库中没有对象记录

Java如何进入临时状态

1】通过new语句刚创建一个对象时 2】当调用Session 的delete()方法,从Session 缓存中删除一个对象时。

2.持久化状态(persisted)

特征:

1】处于Session 缓存中 2】持久化对象数据库中设有对象记录 3】Session 在特定时刻会保持二者同步

Java如何进入持久化状态

1】Session 的save()把临时-》持久化状态 2】Session 的load(),get()方法返回的对象 3】Session 的find()返回的list集合中存放的对象 4】Session 的update(),saveOrupdate()使游离-》持久化

3.游离状态(detached)

特征:

1】不再位于Session 缓存中 2】游离对象由持久化状态转变而来,数据库中可能还有对应记录。

Java如何进入持久化状态-》游离状态

1】Session 的close()方法 2】Session 的evict()方法,从缓存中删除一个对象。提高性能。少用。

总结一下Hibernate的好处:

1.JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。

  1. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作

  2. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。

  3. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 来源: [http://www.linuxidc.com/Linux/2012-12/76684.htm](http://www.linuxidc.com/Linux/2012-12/76684.htm)

Hibernate知识总结

Posted on

Hibernate知识总结

Li-boy 奋斗的蜗牛

关于我

一天进步一点点!!!

26 Mar

Hibernate知识总结


1.Hibernate持久化对象的生命周期 (状态)

(1) 瞬态(自由态) (2) 持久态 (3) 托管(游离态)

1.1自由态

持久化对象的自由态,指的是对象在内存中存在,但是在数据库中并

没有数据与其关联。比如Student student = new Student(),这里

的student对象就是一个自由态的持久化对象。

1.2持久态

持久态指的是持久化对象处于由Hibernate管理的状态,这种状态下

持久化对象的变化将会被同步到数据库中。

session.beginTransaction();

User user = new User();

user.setUserName("James");

user.setUserPwd("123");

session.save(user);

session.getTransaction().commit();

1.3游离态

处于持久态的对象,在其对应的Session实例关闭后,此时对象迚入

游离态。也就是说Session实例是持久态对象的宿主环境,一旦宿主

环境失效,那么持久态对象迚入游离状态。

session.beginTransaction();

User user = new User();

user.setUserName("James");

user.setUserPwd("123");

Integer id = (Integer) session.save(user);

user.setUserPwd("456");

session.getTransaction().commit();

user.setUserPwd("789");

游离态和自由态的区别

区别就在于游离态对象可以再次与Session迚行关联而成为持久态对

象。

session.beginTransaction();

User user = new User();

user.setUserName("James");

user.setUserPwd("123");

Integer id = (Integer) session.save(user);

user.setUserPwd("456");

session.getTransaction().commit();

Session session2 = HibernateUtil.getSessionFactory().getCurrentS

session2.beginTransaction();

user.setUserPwd("789");

session2.update(user);

session2.getTransaction().commit();

自由态对象在数据库中没有数据与其对应,但是游离态对象在数据库

中有数据与其对应,只不过当前对象不在Session环境中而已。从对

象的是否有主键值可以做简单的判断。

session.beginTransaction();

User user = new User();

user.setUserName("James");

user.setUserPwd("123");

System.out.println(user.getId());

Integer id = (Integer) session.save(user);

session.getTransaction().commit();

System.out.println(user.getId());

如果我自己创建一个对象,并且给主键属性赋值,该值还在数据库中

存在,当前对象的状态不也是游离态了?

/* 在Hibernate中根据主键判断对象是自由态还是游离态只是判断的

一个参考点,在Hibernate中还有更复杂的机制来判断一个对象的

状态,比如对象的version等等。

回到自由态

session.beginTransaction();

User user = (User) session.load(User.class, 120);

session.delete(user);

session.getTransaction().commit();

三种状态的转换 :

load和get方法

相同点:

get和load方法都是利用对象的主键值获取相应的对象,并可以使对

象处于持久状态。

不同点:

load方法获取对象时不会立即执行查询操作,而是在第一次使用对象

是再去执行查询操作。如果查询的对象在数据库中不存在,load方法

返回值不会为null,在第一次使用时抛出

org.hibernate.ObjectNotFoundException异常。

使用get方法获取对象时会立即执行查询操作,并且对象在数据库中

不存在时返回null值。

save和persist方法

相同点:

save和persist方法都是将持久化对象保存到数据库中

区别:

sava方法成功执行后,返回持久化对象的ID

persist方法成功执行后,不会返回持久化对象的ID,persist方法是

JPA中推荐使用的方法

save和update方法

save方法是将自由态的对象迚行保存。

update方法是将游离态的对象迚行保存。

update和saveOrUpdate方法

如果一个对象是游离态戒持久态,对其执行update方法后会将对象

的修改同步到数据库中,如果该对象是自由态,则执行update方法

是没有作用的。

在执行saveOrUpdate方法时该方法会自动判断对象的状态,如果为

自由态则执行save操作,如果为游离态戒持久态则执行update操作。

update和merge方法

如果持久化对象在数据库中存在,使用merge操作时迚行同步操作。

如果对象在数据库不存在,merge对象则迚行保存操作。

如果对象是游离状态,经过update操作后,对象转换为持久态。但

是经过merge操作后,对象状态依然是游离态。

saveOrUpdate和merge方法

saveOrUpdate方法和merge方法的区别在于如果session中存在两

个主键值相同的对象,迚行saveOrUpdate操作时会有异常抛出。这

时必须使用merge迚行操作。

session.beginTransaction();

User user = new User();

user.setId(3);

user.setUserName("aaaaaaaa");

user.setUserPwd("123123");

User user2 = (User) session.get(User.class, 3);

session.saveOrUpdate(user);//ERROR

session.getTransaction().commit();

clear方法和flush方法

clear方法是将Session中对象全部清除,当前在Session中的对象由

持久态转换为游离态。flush方法则是将持久态对象的更改同步到数据

库中。

session.beginTransaction();

User user = (User) session.get(User.class, 3);

user.setPassword("111");

session.flush();

session.getTransaction().commit();

2.Hibernate查询

2.1 HQL

HQL(Hibernate Query Language)提供了丰富灵活的查询方式,

使用HQL进行查询也是Hibernate官方推荐使用的查询方式。

HQL在语法结构上和SQL语句十分的相同,所以可以很快的上手进行

使用。使用HQL需要用到Hibernate中的Query对象,该对象丏门执

行HQL方式的操作。

1.查询所有

session.beginTransaction();

String hql = "from User";

Query query = session.createQuery(hql);

List userList = query.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

2.where

session.beginTransaction();

String hql = "from User where userName = 'James'";

Query query = session.createQuery(hql);

List userList = query.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

在HQL中where语句中使用的是持久化对象的属性名,比如上面示例

中的userName。当然在HQL中也可以使用别名:

String hql = "from User as u where u.userName = 'James'";

3.过滤条件

在where语句中还可以使用各种过滤条件,如:=、<>、<、>、>=

、<=、between、not between、in、not in、is、like、and、or

等。

– from Student where age > 20;

– from Student where age between 20 and 30;

– from Student where name is null;

– from Student where name like ‘小%’;

– from Student where name like ‘小%’ and age < 30

4.获取一个不完整对象

一列:

session.beginTransaction();

String hql = "select userName from User"

Query query = session.createQuery(hql);

List nameList = query.list();

for(Object obj:nameList){

System.out.println(obj);

}

session.getTransaction().commit();

5.两列或多列:

session.beginTransaction();

String hql = "select userName,userPwd from User";

Query query = session.createQuery(hql);

List nameList = query.list();

for(Object obj:nameList){

Object[] array = (Object[]) obj;

System.out.println("name:" + array[0]);

System.out.println("pwd:" + array[1]);

}

session.getTransaction().commit();

6.统计和分组查询

session.beginTransaction();

String hql = "select count(/*),max(id) from User";

Query query = session.createQuery(hql);

List nameList = query.list();

for(Object obj:nameList){

Object[] array = (Object[]) obj;

System.out.println("count:" + array[0]);

System.out.println("max:" + array[1]);

}

session.getTransaction().commit();

7.更多写法…

消除重复: select distinct name from Student;

最大: select max(age) from Student;

行数: select count(age),age from Student group by age;

排序: from Student order by age;

HQL占位符

session.beginTransaction();

String hql = "from User where userName = ?";

Query query = session.createQuery(hql);

query.setString(0, "James");

List userList = query.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

HQL引用占位符

session.beginTransaction();

String hql = "from User where userName = :name";

Query query = session.createQuery(hql);

query.setParameter("name", "James");

List userList = query.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

HQL分页

session.beginTransaction();

String hql = "from User";

Query query = session.createQuery(hql);

query.setFirstResult(0);

query.setMaxResults(2);

List userList = query.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

3.Criteria查询

Criteria对象提供了一种面向对象的方式查询数据库。Criteria对象需

要使用Session对象来获得。

一个Criteria对象表示对一个持久化类的查询。

1.查询所有

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

List userList = c.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

2.Where

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.add(Restrictions.eq("userName", "James"));

List userList = c.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

3.Restrictions对象

where...and .... 语句

session.beginTransaction();

Criteria c = session.createCriteria(User.class)

c.add(Restrictions.like("userName", "J"));

c.add(Restrictions.eq("id", 120));

List userList = c.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

where...or .... 语句

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.add(Restrictions.or(Restrictions.eq("userName", "James"),

Restrictions.eq("userName", "Alex")));

List userList = c.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

获取唯一的记录

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.add(Restrictions.eq("id", 120));

User user = (User) c.uniqueResult();

System.out.println(user.getUserName());

session.getTransaction().commit();

分页

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.setFirstResult(0);

c.setMaxResults(5);

List userList = c.list();

for(User user:userList){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

分组与统计

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.setProjection(Projections.sum("id"));

Object obj = c.uniqueResult();

System.out.println(obj);

session.getTransaction().commit();

Projections对象

多个统计与分组

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

ProjectionList projectionList = Projections.projectionList();

projectionList.add(Projections.sum("id"));

projectionList.add(Projections.min("id"));

c.setProjection(projectionList);

Object[] obj = (Object[]) c.uniqueResult();

System.out.println("sum:" + obj[0]);

System.out.println("min:" + obj[1]);

session.getTransaction().commit();

排序

session.beginTransaction();

Criteria c = session.createCriteria(User.class);

c.addOrder(Order.desc("id"));

List list = c.list();

for(User user : list){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

4.使用原生SQL查询

1.查询出后必须封装才可以用:

session.beginTransaction();

String sql = "select id,username,userpwd from t_user";

List list = session.createSQLQuery(sql).list();

for(Object item : list){

Object[] rows = (Object[]) item;

System.out.println("id:" + rows[0] + "username:"

  • rows[1] + "userpwd:" + rows[2]);

}

session.getTransaction().commit();

2.查询出一个集合可以直接用对象操作:

session.beginTransaction();

String sql = "select id,username,userpwd from t_user";

SQLQuery query = session.createSQLQuery(sql).addEntity(User.class);

List list = query.list();

for(User user : list){

System.out.println(user.getUserName());

}

session.getTransaction().commit();

3.查询出一个对象可以直接用对象操作

session.beginTransaction();

String sql = "select id,username,userpwd from t_user where id = 2";

SQLQuery query = session.createSQLQuery(sql).addEntity(User.class);

User user = (User) query.uniqueResult();

System.out.println(user.getUserName());

session.getTransaction().commit();

hibernate 喜欢 热度 (4)

分享

返回首页

上一篇

下一篇

关于

一天进步一点点!!!

导航

Hibernate知识点总结

Posted on

Hibernate知识点总结

Hibernate(面试)知识点总结

Hibernate是目前最流行的开源对象关系映射(ORM)框架。Hibernate采用低侵入式的设计,也即完全采用普通的Java对象(POJO),而不必继承Hibernate的某个基类,或实现Hibernate的某个接口。Hibernate是面向对象的程序设计语言和关系数据库之间的桥梁,Hibernate允许程序开发者采用面向对象的方式来操作关系数据库。

因为我们知道hibernate它能支持透明持久化从这个角度来看它没有侵入性所谓侵入性它没有侵入hibernate任何的API所以它叫轻量级框架,轻量级框架的好处是没有侵入性另外的一个好处是为测试带来了好处,测试非常简单测试就行我们写普通的java应用程序一样不需要什么环境只需要几个jar包就可以了写个main函数一侧就可以了它没有侵入性和测试非常简单 这是它流行的一个原因。

hibernate的优缺点 优点:1、程序更加面向对象; 2、提高了生产率; 3、方便移植(修改配置文件); 4、无侵入性。 缺点: 1、效率比JDBC略差; 2、不适合批量操作。

    3、只能配置一种关联关系

Hibernate有四种查询方案 1、get,load方法,根据id查找对象 2、HQL--hibernate query language(查询对象:Query) 3、Criteria--标准查询语言(查询对象:Criteria,查询条件:Criterion) 4、通过sql来查(查询对象:SQLQuery)

具体

Query/Criteria:

1.Query接口封装了Hibernate强大的对象查询能力,同时也支持数据库的更新操作

2.提供了动态查询的参数绑定功能

3.提供list(),iterator(),scroll()等对象导航方法

4.提供uiqueResult()方法获取单独的对象

5.提供executeUpdate()方法来执行DML语句

6.提供了可移植的分页查询方法

Session:

1、save,presist保存数据,persist在事务外不会产生insert语句。

2、delete,删除对象

3、update,更新对象,如果数据库中没有记录,会出现异常,脱管对象如属性改变需要保存,则调用update方法

4、get,根据ID查,会立刻访问数据库

5、load,根据ID查,(返回的是代理,不会立即访问数据库)

6、saveOrUpdate,merge(根据ID和version的值来确定是否是save或update),调用merge你的对象还是托管的。当不知该对象的状态时可调用该方法

小贴士:瞬时对象id无值,脱管对象有值,hibernate通过该方式判断对象的状态

7、lock(把对象变成持久对象,但不会同步对象的状态)

hibernate的工作原理
1.配置好hibernate的配置文件和与类对应的配置文件后,启动服务器 2.服务器通过实例化Configuration对象,读取hibernate.cfg.xml文件的配置内容,并根据相关的需求建好表或者和表建立好映射关系 3.通过实例化的Configuration对象就可以建立sessionFactory实例,进一步,通过sessionFactory实例可以创建 session对象 4.得到session之后,便可以对数据库进行增删改查操作了,除了比较复杂的全文搜索外,简单的操作都可以通过hibernate封装好的 session内置方法来实现 5.此外,还可以通过事物管理,表的关联来实现较为复杂的数据库设计 优点:hibernate相当于java类和数据库表之间沟通的桥梁,通过这座桥我们就可以做很多事情了

Hibernate 的初始化. 1)创建Configeration类的实例。 它的构造方法:将配置信息(Hibernate config.xml)读入到内存。 一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。

2)创建SessionFactory实例 把Configeration 对象中的所有配置信息拷贝到SessionFactory的缓存中。 SessionFactory的实例代表一个数据库存储员源,创建后不再与Configeration 对象关联。

3)调用SessionFactory创建Session的方法 1】用户自行提供JDBC连接。 Connection con=dataSource.getConnection(); Session s=sessionFactory.openSession(con); 2】让SessionFactory提供连接 Session s=sessionFactory.openSession();

状态转换

临时状态 (transient)

1】不处于Session 缓存中 2】数据库中没有对象记录

Java如何进入临时状态 1】通过new语句刚创建一个对象时 2】当调用Session 的delete()方法,从Session 缓存中删除一个对象时。

持久化状态(persisted)

1】处于Session 缓存中 2】持久化对象数据库中有对象记录 3】Session 在特定时刻会保持二者同步

Java如何进入持久化状态 1】Session 的save()把临时-》持久化状态 2】Session 的load(),get()方法返回的对象 3】Session 的find()返回的list集合中存放的对象 4】Session 的update(),saveOrupdate()使游离-》持久化

游离状态(detached)

1】不再位于Session 缓存中 2】游离对象由持久化状态转变而来,数据库中可能还有对应记录。

Java如何进入持久化状态-》游离状态 1】Session 的close()方法 2】Session 的evict()方法,从缓存中删除一个对象。提高性能。少用。

具体如图:

缓存

主要有session缓存(一级缓存)和sessionfactory缓存(内置缓存和外置缓存(也叫二级缓存))

Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存(Session的一些集合属性包含的数据)。在第一级缓存中,持久化类的每个实例都具有唯一的OID。

SessionFactory的缓存又可以分为两类:

内置缓存(存放SessionFactory对象的一些集合属性包含的数据,SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。)

外置缓存。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。

缓存的范围分为三类。

1 事务范围:缓存只能被当前事务访问。

2 进程范围:缓存被进程内的所有事务共享。

3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。

持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。

在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下四种类型的并发访问策略,每一种策略对应一种事务隔离级别。

事务型、读写型、非严格读写型、只读型

什么样的数据适合存放到第二级缓存中?

1 很少被修改的数据

2 不是很重要的数据,允许出现偶尔并发的数据

3 不会被并发访问的数据

4 参考数据

不适合存放到第二级缓存的数据?

1 经常被修改的数据

2 财务数据,绝对不允许出现并发

3 与其他应用共享的数据。

Hibernate的二级缓存策略的一般过程如下:

1) 条件查询的时候,总是发出一条select /* from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。

2) 把获得的所有数据对象根据ID放入到第二级缓存中。

3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

4) 删除、更新、增加数据的时候,同时更新缓存。

注意几个关键字的含义

inverse="true"表示此表不维护表之间的关系,由另外的表维护。

inverse属性默认是false的,就是说关系的两端都来维护关系。

false代表由己方来维护关系,true代表由对方来维护关系。在一个关系中,只能由一方来维护关系,否则会出问题(解疑中会讲到);同时也必须由一方来维护关系,否则会出现双方互相推卸责任,谁也不管。

可以这样理解,cascade定义的是关系两端对象到对象的级联关系;而inverse定义的是关系和对象的级联关系。

Cascade属性的可能值有

all: 所有情况下均进行关联操作,即save-update和delete。
none: 所有情况下均不进行关联操作。这是默认值。
save-update: 在执行save/update/saveOrUpdate时进行关联操作。
delete: 在执行delete 时进行关联操作。

all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,Student包含多个book,当在对象关系中删除一个book时,此book即成为孤儿节点。

来源: [http://blog.163.com/benbenfafa_88/blog/static/649301622011523909352/](http://blog.163.com/benbenfafa_88/blog/static/649301622011523909352/)

Hibernate总结

Posted on

Hibernate总结

Hibernate总结

看了大约十天的视频,从整体上了解一下hibernate,hibernate的优缺点以及如何搭建hibernate,在上篇博客中已经介绍。

目前在看ssh,但是具体的细节没有研究,只是从整体了解其出现的原因以及如何配置,但是里面涉及到细节部分,暂时不做研究,根据后期的学习,会进行深刻理解。

现在自己的java知识不够,这个阶段需要狂塞,猛汲取,整体上尽量消化。后期再对其进行研究细化。

那我们看一下hibernate中整体的内容:

我们一一介绍其中的内容。

  1. Hibernate出现的原因上篇博客已经介绍,可以参考《Hibernate介绍》
  2. Hibernate中的核心五大接口,在上篇博客中也已经介绍,可以参考《Hibernate介绍》
  3. 如何搭建Hibernate,请参考《八步详解Hibernate的搭建及使用》
  4. 持久化对象的三种状态。

分别为:瞬时状态(Transient),持久化状态(Persistent),离线状态(Detached)。三种状态下的对象的生命周期如下:

三种状态的区别是:瞬时状态的对象:没有被session管理,在数据库没有;持久化状态的对象:被session管理,在数据库存在,当属性发生改变,在清理缓存时,会自动和数据库同步;离线状态:没有被session管理,但是在数据库中存在。 来源: [http://blog.csdn.net/llhhyy1989/article/details/7300599](http://blog.csdn.net/llhhyy1989/article/details/7300599)

5.测试工具Juit。

测试类需要继承TestCase,编写单元测试方法,方法名称必须为test开头,方法没有参数没有返回值,采用public修饰。其中在测试中,查询对象时,使用get或者load两种方法进行加载,这种方法的区别:get不支持延迟加载,而load默认情况下是支持延迟加载。并且get查询对象不存在时,返回null;而load查询对象不存在时,则抛出ObjectNotFoundException异常。

6.悲观锁和乐观锁解释。

悲观锁为了解决并发性,跟操作系统中的进程中添加锁的概念一样。就是在整个过程中在事务提交之前或回滚之前,其他的进程是无法访问这个资源的。悲观锁的实现方式有两种:一种使用数据库中的独占锁;另一种是在数据库添加一个锁的字段。hibernate中声明锁如下:

Account account = (Account)session.get(Account.class, 1, LockMode.UPGRADE);而net.sf.hibernate.LockMode类表示锁模式,当取值LockMode.UPGRADE时,则表示使用悲观锁for update;而乐观锁是为了解决版本冲突的问题。就是在数据库中添加version字段,每次更新时,则把自己的version与数据库中的version进行比较,若是版本相比较低,则不允许进行修改更新。

7.H ibernate中的缓存机制。

缓存是什么呢?缓存是应用程序和数据库之间的内存的一片区域。主要的目的是:为了减少对数据库读取的时间。当查询数据时,首先在缓存中查询,若存在,则直接取出,若不存在,然后再向数据库中查询。所以应该把经常访问数据库的数据放到缓存中,至于缓存中的数据如何不断的置换,这也需要涉及一种淘汰数据的算法。

谈到这个hibernate中的缓存,你想到了什么呢?刚才叙述缓存时,是否感觉很熟悉,感觉从哪也听过似的。嗯呢,是呢,是很熟悉,写着写着就很熟悉,这个刚才的缓存以及缓存的置换算法就和计算机组成中的cache类似。

好吧,来回到我们hibernate中的缓存。

hibernate中的缓存可以分为两种:一级缓存,也称session缓存;二级缓存,是由sessionFactory管理。

那一级缓存和二级缓存有什么区别呢?区别的关键关于:缓存的生命周期,也就是缓存的范围不同。

那首先介绍一下缓存的生命周期,也就是缓存的范围。

1.事务缓存,每个事务都有自己的缓存,当事务结束,则缓存的生命周期同样结束,正如上篇博客中我们提到,对数据库的操作,增删改查都是放到事务中的,和事务保持同步,若是事务提交完毕,一般是不允许是再次对数据库进行操作。所以session是属于事务缓存的。

2.应用缓存,一个应用程序中的缓存,也就是应用程序中的所有事务的缓存。只有当应用程序结束时,此时的缓存的额生命周期结束。二级缓存就是应用缓存。

3.集群缓存,被一台机器或多台机器的进程共享。

这下明白了一级缓存和二级缓存的区别了吧。那一级缓存和二级缓存的共同点是:都是缓存实体属性,

二级缓存一般情况都是由第三方插件实现的。第三方插件如:

EHCache,JbossCache(是由Jboss开源组织提供的),osCache(open symphony),swarmCache。前三种对hibernate中的查询缓存是支持的,后一种是不支持hibernate查询缓存。

那什么是hibernate查询缓存呢?

查询缓存是用来缓存普通属性的,对于实体对象而言,是缓存实体对象的id。 来源: [http://blog.csdn.net/llhhyy1989/article/details/7306009](http://blog.csdn.net/llhhyy1989/article/details/7306009) 8.hql查询。

Hibernate query language。hql查询中关键字不区分大小写,但是类和属性都是区分大小写的。

1.简单属性查询。

单一属性查询,返回属性结果集列表,元素类型和实体类的相应的类型一致。 [java] view plaincopyprint?

  1. List students = session.createQuery("select name from Student").list();
  2. for (Iterator iter=students.iterator(); iter.hasNext();) {
  3. String name = (String)iter.next();
  4. System.out.println(name);
  5. }

//返回结果集属性列表,元素类型和实体类中的属性类型一致

多个属性查询,多个属性查询返回数组对象,对象数组的长度取决于属性的个数,对象数组中的元素类型与实体类中属性一致。 [java] view plaincopyprint?

  1. List students = session.createQuery("select id, name from Student").list();
  2. for (Iterator iter=students.iterator(); iter.hasNext();) {
  3. Object[] obj = (Object[])iter.next();
  4. System.out.println(obj[0] + ", " + obj[1]);
  5. }

2.实体对象查询

List students = session.createQuery("from Student").list();

当然这种hql语句,可以使用别名,as可以省去,如:from Student as s,若是使用select关键字,则必须使用别名。如:select s from Student as s.但是不支持select /* from Student格式。

查询中使用list和Iterate区别:

list查询是直接运行查询的结果,所以只有一句sql语句。而iterate方法则有可能会产生N+1条sql语句。这是怎么回事呢?要理解N+1条语句,首先得弄明白iterate是如何执行查询的?

首先发出一条查询对象ID的语句,然后根据对象的ID到缓存(缓存的概念上篇博客已经提到)中查找,若是存在查询出此对象的其他的属性,否则会发出N条语句,此时的N语句,是刚才第一次查询的记录条数。这种现象就是N+1sql语句。

其中list是默认情况下都发出sql语句,查询出的结果会放到缓存中,但是它不会利用缓存,即使放进去,下次执行时,仍然继续发出sql语句。

而:iterate默认情况下会利用缓存,若是缓存中有则不会发出N+1条语句。

3.条件查询。

这种方式就是传入参数,使用参数占位符“?”。也可以使用“:参数名”

java代码如下: [java] view plaincopyprint?

  1. List students = session.createQuery("select s.id, s.name from Student s where s.name like ?")
  2. .setParameter(0, "%0%")
  3. .list();
  4. List students = session.createQuery("select s.id, s.name from Student s where s.name like :myname")
  5. .setParameter("myname", "%0%")
  6. .list();

    4.使用原生sql语句。

    和咱们原先写入的sql语句一样。在此不介绍了。

    5.外置命名查询。

    这个听起来有点晦涩,怎么理解呢?其实通俗的说就是把hql语句写在外面,写在映射文件中。使用标签:

[html] view plaincopyprint?

  1. <![CDATA[ 1.
  2. select s from Student s where s.id <? 1.
  3. ]]>
那在程序中是如何使用此标签的呢?使用session.getNameQuery(),并进行赋值,代码如下:

[java] view plaincopyprint?

  1. List students = session.getNamedQuery("queryStudent")
  2. .setParameter(0, 10)
  3. .list();

6.查询过滤器。

这个是什么意思呢?过滤器大家很熟悉吧,不熟悉的可以参考我的以前博客<>.原来我们接触过编码过滤器,编码过滤器就是为了避免当时每个页面需要设置编码格式而提出的。这个查询过滤器其实也是这个意思。若是代码都需要某一句sql语句的话,可以考虑使用它。这样可以避免每次都写查询语句。

使用如下:首先在映射文件中配置标签:

[html] view plaincopyprint?

然后程序中如下使用并进行赋值: [java] view plaincopyprint?

  1. session.enableFilter("testFilter")
  2. .setParameter("myid", 10);

7.分页查询。

分页查询,这个肯定不陌生,因为在做drp项目时,做的最多的是分页,当时使用oracle数据库,分页查询涉及到三层嵌套。直接传入的参数为:每页的大小(记录数),页号。

 Hibernate中给我们已经封装好了,只要设置开始的页号以及每页的大小即可,不用亲自动手写嵌套的sql语句。

 代码如下:

[java] view plaincopyprint?

  1. List students = session.createQuery("from Student")
  2. .setFirstResult(1)
  3. .setMaxResults(2)
  4. .list();

8.对象导航查询。

这个什么意思呢?这个只要是用于一个类的属性是另一个类的引用。比如:student类中有一个classes属性。其中的classes也是一个类Class的引用。

当我们查询的时候可以这样使用: [java] view plaincopyprint?

  1. List students = session.createQuery("from Student s where s.classes.name like '%t%'")
  2. .list();

相当于:s.getClasses.getName(),直接使用get后面的属性,然后首字母小写。

这种语法,是不是很熟悉?想想我们在哪是不是也用过?想起来了吗?估计你猜出来啦,呵呵,是JSTL(jsp standard tag library)中。若是想进一步了解,可以参考我的博客哈,当时是转载滴貌似。

9.连接查询。

连接分为:内连接和外连接,其中外连接分为左连接,右连接,完全连接。这个跟数据库中的左右连接其实是一样的。我们通俗解释一下:

左连接:以左边为准,右边即使没哟匹配的,也要把这条记录查询出来,此时没有匹配的右边以null填充。

右连接:以右边为准,左边即使没有匹配的,也要把这条记录查询出来,此时没有匹配的左边以null填充。

完全连接:只要一方存在即可。

内连接:必须两方都存在才可以查询提取此记录。

10.统计查询。

 其实就是查询count的记录数。其中查询出来的额count是long类型。

11.DML风格的操作。

 DML?其实DML=Data Manipulate Language(数据操作语言),举个例子:

[java] view plaincopyprint?

  1. session.createQuery("update Student s set s.name=? where s.id<?")
  2. .setParameter(0, "王斌")
  3. .setParameter(1, 2)
  4. .executeUpdate();

假若原来的名字是:李四,更新完数据库后变成王斌,若是我们此时取出数据,其姓名是李四还是王斌?按照道理应该是王斌,但是结果确实李四,若不信,可以自己去实践一下。

这个原因,是因为更新了数据库,但是缓存中没有更新,才会造成这种数据库和缓存不同步的问题。

所以,我们应该尽量不使用这种形式。扬其长避其短嘛。 来源: [http://blog.csdn.net/llhhyy1989/article/details/7307436](http://blog.csdn.net/llhhyy1989/article/details/7307436)