因此,我尝试使用Hibernate插入30000条记录(最终的解决方案是插入300000条或更多记录)。 我的问题是插入300条记录花费了8-9秒,这非常慢。该数据库是Oracle。我尝试了批处理,但是没有加快速度。
休眠配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
<property name="hibernateProperties">
<props>
<prop key="hibernate.max_fetch_depth">0</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.current_session_context_class">ch.nevis.estivate.util.TransactionAwareSessionContext</prop>
<prop key="javax.persistence.validation.mode">none</prop>
<prop key="hibernate.validator.autoregister_listeners">false</prop>
<prop key="hibernate.validator.apply_to_ddl">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
Java:
@Transactional
public class DataGenerator {
public void generate(int nr) {
System.out.println("START " + new Date());
int q = nr / 100;
Role role = (Role) sessionFactory.getCurrentSession().get(Role.class, new Long(4));
Client client = (Client) sessionFactory.getCurrentSession().get(Client.class, new Long(100));
Unit unit = (Unit) sessionFactory.getCurrentSession().get(Unit.class, new Long(100));
TemplateCollection templateCollection = (TemplateCollection) sessionFactory.getCurrentSession().get(TemplateCollection.class, new Long(100));
for(int i = 0; i < nr; i++) {
User user = generateUser(i, client, templateCollection);
sessionFactory.getCurrentSession().save(user);
Profile profile = generateProfile(i, user, unit, client);
sessionFactory.getCurrentSession().save(profile);
Authorization authorization = generateAuthorization(i, profile, role);
sessionFactory.getCurrentSession().save(authorization);
if (i % q == 0) {
System.out.println(i/q + " % " + new Date());
}
if (i % 10 == 0) { // the batch_size is 30 but I save 3 entities in one go
sessionFactory.getCurrentSession().flush();
sessionFactory.getCurrentSession().clear();
}
}
System.out.println("END " + new Date());
}
请问有什么提示吗?
也许Hibernate不适合加载许多记录?
谢谢,
V。
------------更新-------------
删除了自定义会话上下文类(即正在使用Spring的CurrentSessionContext),但没有提高速度。
------------更新2 -------------
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("file:/......./applicationContext-testDataGenerator.xml");
DataGenerator dataGenerator= ctx.getBean("dataGenerator", DataGenerator.class);
dataGenerator.generate(10000);
}
答案 0 :(得分:3)
我认为您应该将冲洗部分移到循环之外,并且只执行一次。
这将加快您的代码。
batch_size 只是告诉Hibernate将多少个SQL命令组合在一起。
也许可以增加 batch_size 来加快插入阶段。
答案 1 :(得分:1)
如果需要加快插入许多记录的速度,则应尝试使用本机查询插入jdbcTemplate,以进行实体转换,从而避免了查询转换。还要批量执行(假设有1000次)
答案 2 :(得分:0)
您应该用@Transactional
注释方法,以便在所有方法流中重用同一会话,否则sessionFactory将为每次getCurrentSession()调用建立一个新会话。
[编辑]
确保generate方法是从外部调用的。
创建一个Main类,使用spring向其注入DataGenerator的实例,并在注入的实例上调用generate()。这样,将应用spring transactionInterceptor并正确处理会话实例
答案 3 :(得分:0)
如前所述,在保存(甚至获取)如此大量的数据时使用休眠模式不是一个好主意(如果您处理的数据非常大,则有可能以OutOfMem结尾,因为休眠会在上下文中存储对象的多个副本,直到您的会话有效并且GC无法清除它们为止),但是如果您确实需要它,则最好使用无状态会话,这样可以防止您创建大型对象大量无用的物体。
另外,请确保您从外部调用generate()
方法,如果您从同一类@Transactional
调用该方法将无效。
答案 4 :(得分:0)
如果仍然很慢,请尝试执行以下操作:
List<User> users = new ArrayList<>();
List<Profile> profiles = new ArrayList();
List<Authorization> authorizations = new ArrayList<>();
for(int i = 0; i < nr; i++) {
users.add(generateUser(i, client, templateCollection));
profiles.add(generateProfile(i, user, unit, client));
authorizations.add(generateAuthorization(i, profile, role));
}
users.forEach(sessionFactory.getCurrentSession()::save);
profiles.forEach(sessionFactory.getCurrentSession()::save);
authorizations.forEach(sessionFactory.getCurrentSession()::save);
不确定是否会有所帮助,但可能会有所帮助。在尝试将批处理插入多个表时,我得到了奇怪的结果(我相信,在很多情况下,像您一样执行插入操作时,批处理插入是不起作用的,例如,将entity1插入表A,将entity2插入表B,将entity3插入表A ,依此类推...,但不要在此引用我的意思