Spring和hibernate:query.list()的执行次数不会超过两次

时间:2016-04-12 12:59:50

标签: java spring hibernate

我在java中有一个类,有两个类似于这里的方法。

 public Object noOfEmployees() {

        List<Employee> emp = null;
        String u = user.getUserName();

        if ("user1".equals(u)) {

            Query query = getHibernateTemplate().getSessionFactory().openSession()
                    .createSQLQuery("select * from employee where job='System Analyst'")
                    .addEntity(EMPLOYEE.class);

            emp = query.list();

             getHibernateTemplate().getSessionFactory().openSession().close();

        } else if ("user2".equals(u)) { 

            Query query = getHibernateTemplate().getSessionFactory().openSession()
                    .createSQLQuery("select * from employee where job='DBA'")
                    .addEntity(EMPLOYEE.class);

            emp = query.list();
             getHibernateTemplate().getSessionFactory().openSession().close();

        } 
        return emp.size();
    }

当我运行应用程序时,这就是我得到输出的方式:

  1. 以&#39; user2&#39;

    登录

    休眠:从员工中选择*,其中job =&#39; DBA&#39;

    Hibernate:从员工中选择*,其中job =&#39; DBA&#39;和排名=&#39; 2&#39;

    休眠:从员工中选择*,如果存在=&#39;是&#39;

  2. 以&#39; user1&#39;

    登录

    Hibernate:从员工中选择*,其中job =&#39; System Analyst&#39;

    Hibernate:从员工中选择*,其中job =&#39; System Analyst&#39;和排名=&#39; 3&#39;

    休眠:从员工中选择*,如果存在=&#39;是&#39;

  3. 再次登录为&#39; user2&#39;,前两个方法被执行。

    休眠:从员工中选择*,其中job =&#39; DBA&#39;

    Hibernate:从员工中选择*,其中job =&#39; DBA&#39;和排名=&#39; 2&#39;

  4. 当我以任何用户身份登录时,这次甚至第一种方法都没有被执行。

  5. 我注意到遇到 query.list()时代码卡住了。我知道不建议使用hibernateTemplate,但整个应用程序都是使用它编写的。我刚刚开始学习弹簧和冬眠。一旦我对这些事情感到满意,我就会开始做出改变。

    任何与query.list()性能相关的建议以及改进代码的方法都非常受欢迎。

    谢谢!

3 个答案:

答案 0 :(得分:0)

显然,问题在于此代码

Query query = getHibernateTemplate().getSessionFactory().openSession().

...
getHibernateTemplate().getSessionFactory().openSession().close();

使用此getHibernateTemplate().getSessionFactory().openSession().close(),您将获得一个新会话并关闭它!

你应该使用HQL

Query query = session.createQuery("from Employee where job='System Analyst'");
List<Employee> emp = query.list();

使用Hibernate Template的方式完全不正确。

参考如何使用

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/classic-spring.html

一个例子

public class ProductDaoImpl {

    private HibernateTemplate hibernateTemplate;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    public Collection loadProductsByCategory(final String category) throws DataAccessException {
        return this.hibernateTemplate.execute(new HibernateCallback() {
            public Object doInHibernate(Session session) {
                Criteria criteria = session.createCriteria(Product.class);
                criteria.add(Expression.eq("category", category));
                criteria.setMaxResults(6);
                return criteria.list();
            }
        };
    }

}

答案 1 :(得分:0)

你的代码在很多层面都存在缺陷......对于初学者来说,你不应该使用HibernateTemplate,除非你是一个非常古老的应用程序,否则使用普通的SessionFactory。有关详细信息,请参阅http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate-straight

第二个使用Spring时使用Spring来管理你的资源,在这种情况下是Session,或者如果你想自己做,至少要管理它!

因此,简而言之,请使用SessionFactory并使用getCurrentSession代替openSession。并使用正确的查询。

@Autowired
private SessionFactory sf;

@Transactional
public Long noOfEmployees() {
    final String query = "select count(*) from employee where job=:job";
    Query q = sf.getCurrentSession().createSQLQuery(query);
    if ("user1".equals(u)) {
        q.setParameter("job", "System Analyst");
    } else if ("user2".equals(u) ) {
        q.setParameter("job", "DBA");
    }
    return (Long) query.uniqueResult();
}

@Transactional会让spring管理资源,假设您在上下文中有<tx:annotation-driven />并正确添加了HibernateTransactionManager

答案 2 :(得分:0)

我试图在某种程度上改变我的多级错误代码。感谢@ M.Deinum和@ v.ladynev的快速反应。

下面给出的是仅提到从HibernateTemplate转移到SessionFactory的更改的片段:

//IndexService

    @Transactional
    public class IndexService {

        User user;
        SessionFactory sf;

        public IndexService(User user, SessionFactory sf) {

            this.user = user;
            this.sf = sf;
        }

    //This method is used to get the number of employees based on users.

    public Object noOfEmployees() {

        String u = user.getUserName();

        final String query = "select count(*) from employee where job=:job";

        Query q = sf.getCurrentSession().createSQLQuery(query);

        if ("user1".equals(u)) {

            q.setParameter("job", "System Analyst");

        } else if ("user2".equals(u) ) {

            q.setParameter("job", "DBA");

        }
        return q.uniqueResult();
    }
    --------------------------------------------------------------------------------------
    //Index

    @Controller
    @Transactional
    public class Index {

        @Autowired
        User user;
        @Autowired
        SessionFactory sf;

        @RequestMapping("/index")
        public ModelAndView getIndex() {

            System.out.println("user.getUserName() In Index = " + user.getUserName());

            ModelAndView modelAndView = new ModelAndView("index");

            IndexService indexService = new IndexService(user, sf);

            modelAndView.addObject("noOfEmployees", indexService.noOfEmployees());

            return modelAndView;
        }
    }
    --------------------------------------------------------------------------------------
    //spring-servlet.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">


        <tx:annotation-driven transaction-manager="transactionManager" />

        <bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url"
                value="jdbc:mysql://localhost/database_name"></property>
            <property name="username" value="user"></property>
            <property name="password" value="password"></property>
        </bean>

        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource" ref="basicDataSource"></property>

            <property name="mappingResources" value="myBeans.hbm.xml" />

            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                    <prop key="hibernate.show_sql">true</prop>
                </props>
            </property>
        </bean>


<bean id="transactionManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>

    </beans>

从HibernateTemplate更改为SessionFactory时遇到的问题:

1. SessionFactory的

在索引类中,

@Autowired SessionFactory sf;

并将其作为参数传递。

IndexService indexService = new IndexService(user,sf);

2.没有Hibernate Session绑定到线程,并且配置不允许在这里创建非事务性的

我也把@Transactional放在索引之上。它是我应用程序中的控制器。

再次感谢@ M.Deinum和@ v.ladynev!