- 浏览: 266512 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
honey_fansy:
你这是使用,不是实现吧。。。
java 简单实现AES/DES加解密 -
www314599782:
厉害,知道怎么横向了
JXLS Demo -
lijiejava:
...
Hessian 简单例子 -
dxqrr:
good..........
Spring 生命周期 -
zhaokai2daisai:
你需要先在iReport-5.6.0\iReport-5.6. ...
JasperReport 简单使用(数据库源为数据库)
当Hibernate或Ibatis在处理一对多的时候都存在n+1问题。
创建数据库
ACCOUNT 表
ORDERS 表
创建JavaBean
Account.java
Orders.java
一、使用Ibatis查询
SqlMapConfig.xml配置
n1.ibatis.xml 配置
groupby.ibatis.xml 配置
测试代码
执行以上代码,log4j打印如下:
查看以上log,发现执行了3条查询语句.
将SqlMapConfig.xml中的setting 节点中的lazyLoadingEnabled属性设为true
再次执行之前queryN1测试代码,log4j打印如下
查看log,依然有3条查询语句,只是查询的时机不一样了。当设置SqlMapConfig.xml中的setting 节点中的lazyLoadingEnabled属性设为true时(启动ibatis懒加载),ibatis会生成代理对对象,当集合元素真正使用时才执行查询语句(和hibernate类似)。
目前来看:至少在ibatis中启用或不启用懒加载,都不可以解决n+1问题.而在ibatis中使用groupby是一个解决方案.
测试代码如下:
执行以上测试代码,log打印如下
查看以上log,发现只有1条查询语句,解决了n+1问题。
目前看来,n+1问题算是解决了,可是配置文件搞得很复杂。
ibatis作为sql mapper并不是orm,非把ibatis当hibernate玩,个人认为这样并没有多大意义。
二 使用hibernate查询
hibernate.cfg.xml配置
Account.hibernate.xml 配置
Orders.hibernate.xml 配置
a.hibernate 1对多 n+1
测试代码
执行以上测试代码,打印log如下:
查看以上log,发现3条查询语句。n+1 问题重现了。因为hibernate对集合查询默认是懒加载的,所以从以上打印log发现,只用在要使用集合时,hibernate才去执行查询。
将Account.hibernate.xml中set节点的lazy属性设置为false,如下
再次执行query1()测试代码,log打印如下:
查看以上log,发现依然是3条查询语句,只是查询在一开始就全部执行了。
b.hibernate 多对1 n+1
测试代码
执行以上测试代码,log如下:
查看以上log,发现3条查询语句。
倘若将Account.hibernate.xml中set节点的lazy属性设置为false,如下
再次执行query2(),log打印如下:
查看以上log,发现5条查询语句。第一查询语句用来查询Orders信息,而Orders对象中的Account实例变量默认是懒加载的,所以当使用account变量时,hibernate才进行查询,由于Account对象中的ordersSet集合不启用懒加载。所以每次查询Account时会附带查询一次Orders.
c.hibernate 使用iterate n+1
测试代码
执行以上测试代码,log打印语句如下:
查看以上log,发现有5条查询语句。第一条查询Account对象的accountId列表。当迭代使用Account时,hibernate会通过查询到的accountId在内存中找,如果找到则直接使用,如果为未找到则做一次查询。而把iterate查询归纳为n+1查询感觉不妥当,写在这里是想说明iterate没用好会产生n+1次查询或者更多。
如果将query3()中的迭代对象改为Orders,就会有很刺激的事,如果再将Account中的ordersSet懒加载去除(lazy=false),就更有意思了。
在hibernate中要解决n+1可以通过left join fetch。
将query1() 的hql该为from Account as account left join fetch account.ordersSet
重新执行则只有一条查询语句。
总结:不管是hibernate 还是ibatis 如果对象设计中有主从对象(主从对象指:一个对象中包含另一个对象,包含对象为主对象,被包含对象为从对象,从对象可为普通javabean或集合)都有可能碰到n+1问题,其中1指进行一条语句查询到n个主对象,而n指n个主对象要将从对象关联出来要进行n次查询。而解决方案不管怎样就是通过数据库join查询。而hibernate比较复杂点有很多缓存可用,所以具体的时候会有点差异。n+1并不是问题,更是一种策略。
创建数据库
ACCOUNT 表
ACCOUNT_ID |
1 |
2 |
ORDERS 表
ORDER_ID | ACCOUNT_ID |
1 | 1 |
2 | 1 |
3 | 1 |
4 | 2 |
5 | 2 |
6 | 2 |
创建JavaBean
Account.java
public class Account { private Integer accountId; private Set<Orders> ordersSet = new HashSet<Orders>(); // 省略 getter setter public String toString() { return "accountId:" + accountId; } }
Orders.java
public class Orders { private Integer orderId; private Account account; // 省略getter setter public String toString() { return "orderId:"+orderId; } }
一、使用Ibatis查询
SqlMapConfig.xml配置
<sqlMapConfig> <settings cacheModelsEnabled="true" enhancementEnabled="false" lazyLoadingEnabled="false" maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="true" /> <transactionManager type="JDBC"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="JDBC.ConnectionURL" value="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=TEST" /> <property name="JDBC.Username" value="xiao" /> <property name="JDBC.Password" value="xiao" /> </dataSource> </transactionManager> <sqlMap resource="ibatis/n1.ibatis.xml" /> <sqlMap resource="ibatis/groupby.ibatis.xml" /> </sqlMapConfig>
n1.ibatis.xml 配置
<sqlMap namespace="N1"> <typeAlias alias="Account" type="bean.Account"/> <resultMap id="ResultAccountInfoMap" class="bean.Account"> <result property="accountId" column="ACCOUNT_ID" /> <result property="ordersSet" select="N1.getOrderInfoList" column="ACCOUNT_ID"/> </resultMap> <resultMap id="ResultOrderInfoMap" class="bean.Orders"> <result property="orderId" column="ORDER_ID" /> <result property="account.accountId" column="ACCOUNt_Id" /> </resultMap> <select id="getAccountInfoList" resultMap="ResultAccountInfoMap"> select account_Id from ACCOUNT </select> <select id="getOrderInfoList" resultMap="ResultOrderInfoMap"> select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = #value# </select> </sqlMap>
groupby.ibatis.xml 配置
<sqlMap namespace="GroupBy"> <resultMap id="ResultAccountInfoMap" class="bean.Account" groupBy="accountId"> <result property="accountId" column="account_Id" /> <result property="ordersSet" resultMap="GroupBy.ResultOrderInfoMap"/> </resultMap> <resultMap id="ResultOrderInfoMap" class="bean.Orders" groupBy="orderId"> <result property="orderId" column="ORDER_ID" /> <result property="account.accountId" column="ACCOUNT_ID" /> </resultMap> <select id="getAccountInfoList" resultMap="ResultAccountInfoMap"> select ACCOUNT.ACCOUNT_ID AS ACCOUNT_ID ,ORDERS.ORDER_ID AS ORDER_ID from ACCOUNT join ORDERS on ACCOUNT.account_Id=ORDERS.ACCOUNT_ID group by ACCOUNT.ACCOUNT_ID,ORDERS.ORDER_ID </select> </sqlMap>
测试代码
public static void queryN1() throws SQLException, IOException{ Reader reader=Resources.getResourceAsReader("ibatis/SqlMapConfig.xml"); SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); List<Account> accountList=sqlMapClient.queryForList("N1.getAccountInfoList"); for(Account account:accountList){ System.out.println("############"+account+"############"); for(Orders orders:account.getOrdersSet()){ System.out.println("############"+orders+"############"); } } }
执行以上代码,log4j打印如下:
[size=xx-small]2012-08-07 10:19:52,000-[HL] DEBUG main java.sql.Connection - {conn-100000} Connection 2012-08-07 10:19:52,000-[HL] DEBUG main java.sql.Connection - {conn-100000} Preparing Statement: select account_Id from ACCOUNT 2012-08-07 10:19:52,031-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Executing Statement: select account_Id from ACCOUNT 2012-08-07 10:19:52,031-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Parameters: [] 2012-08-07 10:19:52,031-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Types: [] 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.Connection - {conn-100000} Preparing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Executing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Parameters: [1] 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Types: [java.lang.Integer] 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Executing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Parameters: [2] 2012-08-07 10:19:52,078-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100003} Types: [java.lang.Integer][/size][size=xx-small][/size] ############accountId:1############ ############orderId:3############ ############orderId:2############ ############orderId:1############ ############accountId:2############ ############orderId:5############ ############orderId:6############ ############orderId:4############
查看以上log,发现执行了3条查询语句.
将SqlMapConfig.xml中的setting 节点中的lazyLoadingEnabled属性设为true
<settings cacheModelsEnabled="true" enhancementEnabled="false" lazyLoadingEnabled="true" maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="true" />
再次执行之前queryN1测试代码,log4j打印如下
2012-08-07 10:26:42,468-[HL] DEBUG main java.sql.Connection - {conn-100000} Connection 2012-08-07 10:26:42,468-[HL] DEBUG main java.sql.Connection - {conn-100000} Preparing Statement: select account_Id from ACCOUNT 2012-08-07 10:26:42,515-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Executing Statement: select account_Id from ACCOUNT 2012-08-07 10:26:42,515-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Parameters: [] 2012-08-07 10:26:42,515-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Types: [] ############accountId:1############ 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.Connection - {conn-100003} Connection 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.Connection - {conn-100003} Preparing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100004} Executing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100004} Parameters: [1] 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100004} Types: [java.lang.Integer] ############orderId:3############ ############orderId:1############ ############orderId:2############ ############accountId:2############ 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.Connection - {conn-100006} Connection 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.Connection - {conn-100006} Preparing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100007} Executing Statement: select ORDER_ID,ACCOUNT_ID from ORDERS where ACCOUNT_ID = ? 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100007} Parameters: [2] 2012-08-07 10:26:42,562-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100007} Types: [java.lang.Integer] ############orderId:5############ ############orderId:4############ ############orderId:6############
查看log,依然有3条查询语句,只是查询的时机不一样了。当设置SqlMapConfig.xml中的setting 节点中的lazyLoadingEnabled属性设为true时(启动ibatis懒加载),ibatis会生成代理对对象,当集合元素真正使用时才执行查询语句(和hibernate类似)。
目前来看:至少在ibatis中启用或不启用懒加载,都不可以解决n+1问题.而在ibatis中使用groupby是一个解决方案.
测试代码如下:
public static void queryGroupBy() throws SQLException, IOException{ Reader reader=Resources.getResourceAsReader("ibatis/SqlMapConfig.xml"); SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); List<Account> accountList=sqlMapClient.queryForList("GroupBy.getAccountInfoList"); for(Account account:accountList){ System.out.println("############"+account+"############"); for(Orders orders:account.getOrdersSet()){ System.out.println("############"+orders+"############"); } } }
执行以上测试代码,log打印如下
2012-08-07 10:36:12,328-[HL] DEBUG main java.sql.Connection - {conn-100000} Connection 2012-08-07 10:36:12,328-[HL] DEBUG main java.sql.Connection - {conn-100000} Preparing Statement: select ACCOUNT.ACCOUNT_ID AS ACCOUNT_ID ,ORDERS.ORDER_ID AS ORDER_ID from ACCOUNT join ORDERS on ACCOUNT.account_Id=ORDERS.ACCOUNT_ID group by ACCOUNT.ACCOUNT_ID,ORDERS.ORDER_ID 2012-08-07 10:36:12,359-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Executing Statement: select ACCOUNT.ACCOUNT_ID AS ACCOUNT_ID ,ORDERS.ORDER_ID AS ORDER_ID from ACCOUNT join ORDERS on ACCOUNT.account_Id=ORDERS.ACCOUNT_ID group by ACCOUNT.ACCOUNT_ID,ORDERS.ORDER_ID 2012-08-07 10:36:12,359-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Parameters: [] 2012-08-07 10:36:12,359-[HL] DEBUG main java.sql.PreparedStatement - {pstm-100001} Types: [] ############accountId:1############ ############orderId:3############ ############orderId:2############ ############orderId:1############ ############accountId:2############ ############orderId:4############ ############orderId:6############ ############orderId:5############
查看以上log,发现只有1条查询语句,解决了n+1问题。
目前看来,n+1问题算是解决了,可是配置文件搞得很复杂。
ibatis作为sql mapper并不是orm,非把ibatis当hibernate玩,个人认为这样并没有多大意义。
二 使用hibernate查询
hibernate.cfg.xml配置
<hibernate-configuration> <session-factory> <property name="dialect">org.hibernate.dialect.SQLServerDialect</property> <property name="connection.url">jdbc:sqlserver://127.0.0.1:1433;DatabaseName=TEST</property> <property name="connection.username">xiao</property> <property name="connection.password">xiao</property> <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> <property name="show_sql">true</property> <mapping resource="hibernate/Account.hibernate.xml"/> <mapping resource="hibernate/Orders.hibernate.xml"/> </session-factory> </hibernate-configuration>
Account.hibernate.xml 配置
<hibernate-mapping> <class name="bean.Account" table="ACCOUNT" > <id name="accountId" column="ACCOUNT_ID" /> <set name="ordersSet" > <key column="ACCOUNT_ID"/> <one-to-many class="bean.Orders"/> </set> </class> </hibernate-mapping>
Orders.hibernate.xml 配置
<hibernate-mapping> <class name="bean.Orders" table="ORDERS"> <id name="orderId" column="ORDER_ID"/> <many-to-one name="account" class="bean.Account" column="ACCOUNT_ID"/> </class> </hibernate-mapping>
a.hibernate 1对多 n+1
测试代码
public static void query1(){ Configuration config = new Configuration().configure("hibernate/hibernate.cfg.xml"); SessionFactory factory = config.buildSessionFactory(); Session session = factory.openSession(); System.out.println("==========start query=========="); Query query=session.createQuery("from Account as account"); List<Account> accountList=query.list(); for(Account account:accountList){ System.out.println("############"+account+"############"); for(Orders orders:account.getOrdersSet()){ System.out.println("############"+orders+"############"); } } session.close(); }
执行以上测试代码,打印log如下:
==========start query========== Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_ from ACCOUNT account0_ ############accountId:1############ Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############orderId:2############ ############orderId:1############ ############orderId:3############ ############accountId:2############ Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############orderId:6############ ############orderId:5############ ############orderId:4############
查看以上log,发现3条查询语句。n+1 问题重现了。因为hibernate对集合查询默认是懒加载的,所以从以上打印log发现,只用在要使用集合时,hibernate才去执行查询。
将Account.hibernate.xml中set节点的lazy属性设置为false,如下
<set name="ordersSet" lazy="false"> <key column="ACCOUNT_ID"/> <one-to-many class="bean.Orders"/> </set>
再次执行query1()测试代码,log打印如下:
==========start query========== Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_ from ACCOUNT account0_ Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############accountId:1############ ############orderId:1############ ############orderId:3############ ############orderId:2############ ############accountId:2############ ############orderId:5############ ############orderId:4############ ############orderId:6############
查看以上log,发现依然是3条查询语句,只是查询在一开始就全部执行了。
b.hibernate 多对1 n+1
测试代码
public static void query2(){ Configuration config = new Configuration().configure("hibernate/hibernate.cfg.xml"); SessionFactory factory = config.buildSessionFactory(); Session session = factory.openSession(); System.out.println("==========start query=========="); Query query=session.createQuery("from Orders"); List<Orders> ordersSet=query.list(); for(Orders orders:ordersSet){ System.out.println("############"+orders+"############"); System.out.println("############"+orders.getAccount()+"############"); } session.close(); }
执行以上测试代码,log如下:
==========start query========== Hibernate: select orders0_.ORDER_ID as ORDER1_1_, orders0_.ACCOUNT_ID as ACCOUNT2_1_ from ORDERS orders0_ ############orderId:1############ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? ############accountId:1############ ############orderId:2############ ############accountId:1############ ############orderId:3############ ############accountId:1############ ############orderId:4############ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? ############accountId:2############ ############orderId:5############ ############accountId:2############ ############orderId:6############ ############accountId:2############
查看以上log,发现3条查询语句。
倘若将Account.hibernate.xml中set节点的lazy属性设置为false,如下
<set name="ordersSet" lazy="false"> <key column="ACCOUNT_ID"/> <one-to-many class="bean.Orders"/> </set>
再次执行query2(),log打印如下:
==========start query========== Hibernate: select orders0_.ORDER_ID as ORDER1_1_, orders0_.ACCOUNT_ID as ACCOUNT2_1_ from ORDERS orders0_ ############orderId:1############ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############accountId:1############ ############orderId:2############ ############accountId:1############ ############orderId:3############ ############accountId:1############ ############orderId:4############ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############accountId:2############ ############orderId:5############ ############accountId:2############ ############orderId:6############ ############accountId:2############
查看以上log,发现5条查询语句。第一查询语句用来查询Orders信息,而Orders对象中的Account实例变量默认是懒加载的,所以当使用account变量时,hibernate才进行查询,由于Account对象中的ordersSet集合不启用懒加载。所以每次查询Account时会附带查询一次Orders.
c.hibernate 使用iterate n+1
测试代码
public static void query3(){ Configuration config = new Configuration().configure("hibernate/hibernate.cfg.xml"); SessionFactory factory = config.buildSessionFactory(); Session session = factory.openSession(); System.out.println("==========start query=========="); Query query=session.createQuery("from Account"); Iterator<Account> iterator=query.iterate(); while(iterator.hasNext()){ Account account=iterator.next(); System.out.println("############"+account+"############"); System.out.println("############"+account.getOrdersSet()+"############"); } session.close(); }
执行以上测试代码,log打印语句如下:
==========start query========== Hibernate: select account0_.ACCOUNT_ID as col_0_0_ from ACCOUNT account0_ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? ############accountId:1############ Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############[orderId:3, orderId:2, orderId:1]############ Hibernate: select account0_.ACCOUNT_ID as ACCOUNT1_0_0_ from ACCOUNT account0_ where account0_.ACCOUNT_ID=? ############accountId:2############ Hibernate: select ordersset0_.ACCOUNT_ID as ACCOUNT2_1_, ordersset0_.ORDER_ID as ORDER1_1_, ordersset0_.ORDER_ID as ORDER1_1_0_, ordersset0_.ACCOUNT_ID as ACCOUNT2_1_0_ from ORDERS ordersset0_ where ordersset0_.ACCOUNT_ID=? ############[orderId:6, orderId:5, orderId:4]############
查看以上log,发现有5条查询语句。第一条查询Account对象的accountId列表。当迭代使用Account时,hibernate会通过查询到的accountId在内存中找,如果找到则直接使用,如果为未找到则做一次查询。而把iterate查询归纳为n+1查询感觉不妥当,写在这里是想说明iterate没用好会产生n+1次查询或者更多。
如果将query3()中的迭代对象改为Orders,就会有很刺激的事,如果再将Account中的ordersSet懒加载去除(lazy=false),就更有意思了。
在hibernate中要解决n+1可以通过left join fetch。
将query1() 的hql该为from Account as account left join fetch account.ordersSet
重新执行则只有一条查询语句。
总结:不管是hibernate 还是ibatis 如果对象设计中有主从对象(主从对象指:一个对象中包含另一个对象,包含对象为主对象,被包含对象为从对象,从对象可为普通javabean或集合)都有可能碰到n+1问题,其中1指进行一条语句查询到n个主对象,而n指n个主对象要将从对象关联出来要进行n次查询。而解决方案不管怎样就是通过数据库join查询。而hibernate比较复杂点有很多缓存可用,所以具体的时候会有点差异。n+1并不是问题,更是一种策略。
发表评论
-
Hibernate(一)简单CURD
2013-09-06 17:43 1095Person.java package com; im ... -
自定义Ibatis生成器
2013-08-28 11:35 2042用了Ibatis一年,感觉 ... -
Ibatis 入门
2013-08-27 14:43 946Ibatis是一个轻便的sqlMa ... -
ibatis uitl
2013-08-22 07:53 0fadssssssssssssssssssssssssss ... -
requirement
2013-05-24 07:37 0快件收发系统 普通客户 订单下达,订单跟踪(不用登 ... -
ibatis部分源码窥探
2011-12-19 11:09 1884ibatis2.3.4部分类结构图 SqlMapClie ... -
ibatis 执行sqlserver存储过程
2011-11-29 21:14 5747sqlserver 存储过程: create proce ...
相关推荐
maven3+struts2+spring+ibatis,本来是用maven3+struts2+spring+hibernate但考虑到hibernate在多表级联查询的时候执行效率不高,所以改用性能更好不过sql比较麻烦的的ibatis,本项目只有登录和插入数据,仅供参考: ...
但 iBATIS 提供了两种方式来处理关联查询:N+1 次查询和新的查询方式。 1. **N+1 次查询** 这种方式在 SQL 映射文件中通过 `select` 属性指定一个单独的查询语句。虽然这种方法会导致额外的数据库读取操作,但可以...
10. **最佳实践**:分享一些使用 iBatis 的最佳实践,如避免N+1查询问题,提高性能的技巧等。 通过学习这个 iBatis 的 demo,开发者可以更好地理解和掌握 iBatis 在实际开发中的运用,提升数据访问层的构建能力。...
支持代码生成工具,避免N+1查询问题。 - **缺点**:相较于Hibernate等框架来说,知名度和社区支持相对较低。 ### 3. 在具体项目中如何选择合适的技术栈 在实际项目开发过程中,选择合适的数据库访问技术是至关重要...
6.2.3 避免N+1查询问题 105 6.3 继承 107 6.4 其他用途 109 6.4.1 使用语句类型和DDL 109 6.4.2 处理超大型数据集 109 6.5 小结 115 第7章 事务 116 7.1 事务是什么 116 7.1.1 一个简单的银行转账示例 116 7.1.2 ...
8. **最佳实践与案例分析**:提供实际开发中的最佳实践,如如何优化SQL,避免N+1问题,以及在大型项目中如何有效地组织和管理映射文件。 9. **与其他框架集成**:探讨如何将iBatis与Spring、Struts等其他框架整合,...
26. **避免N+1 Select(1:M和M:N)** - 在处理1:M或M:N关系时,同样需要考虑避免多次查询的问题。 27. **组合键值或多个复杂参数属性** - 可以通过组合键或多个参数属性来处理复杂的查询需求。 28. **缓存...
6. **Hibernate最佳实践**:在使用Hibernate时,应注意避免过多的N+1查询,合理配置缓存策略,使用预编译的SQL语句(HQL或Criteria的CriteriaQuery),以及遵循事务管理的最佳实践,确保数据的一致性和完整性。...
但要注意性能优化,如避免过多的懒加载和N+1查询问题。 2. **iBatis**:适合对SQL有高度控制需求的项目,可以灵活地调整SQL语句,性能通常优于ORM框架。需要注意的是,SQL的维护和版本控制需要额外注意。 3. **JSON...
在JavaEE开发中,ORM(Object-Relational Mapping,对象关系映射)框架是...在处理大数据量或复杂业务逻辑时,还需注意优化查询,避免N+1查询问题,以及注意事务隔离级别和并发控制,确保系统的稳定性和数据的一致性。
在使用Hibernate时,应遵循一些最佳实践,如合理设计实体关系,避免N+1查询问题,使用缓存提高性能,以及适当地处理事务。 总之,Hibernate培训的目标是让学员能够熟练掌握O/R Mapping的概念,灵活运用Hibernate...
面试中可能会询问如何通过MyBatis进行SQL优化,包括使用合适的索引、避免N+1查询问题、合理使用缓存以及利用MyBatis提供的内置方法如foreach进行批量处理。 6. MyBatis与其他框架整合:MyBatis是一个轻量级的框架,...
ext学习笔记一 小试iBatis RIA(Rich Internet Application)的现状和未来 Java应用中域名解析不过期的解决方法 Java编程那些事儿45—数组使用示例1 一步步熟悉OFBiz 用Java做客户端调用.NET写...
11、iBatis与Hibernate有什么不同? 122 12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么...
这种方式可能导致“1+N”查询问题,即查询一次主数据后,还需要为每条主数据执行N次子查询。 多对多映射示例: - 逻辑模型:一个User可以属于多个Group,一个Group也可以有多个User。 - XML配置中,通常需要中间表...
11、iBatis与Hibernate有什么不同? 122 12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么...
11、iBatis与Hibernate有什么不同? 122 12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么...
11、iBatis与Hibernate有什么不同? 133 12、写Hibernate的一对多和多对一双向关联的orm配置? 134 9、hibernate的inverse属性的作用? 134 13、在DAO中如何体现DAO设计模式? 134 14、spring+Hibernate中委托方案怎么...