- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我试图理解为什么在创建新实体并在应用程序运行时持久化它之后,在检索这些实体的列表时,应该从数据库中检索新实体,但不是吗?
例如:
我创建了一个新实体(从 UI)并像这样成功地持久化它:
@Repository
public class BaseDAOHibernate {
Session session;
public BaseDAOHibernate() {
session = HibernateUtils.getSessionFactory().openSession();
}
public void save(Object object) {
Transaction tx = session.beginTransaction();
session.save(object);
tx.commit();
}
...
我已验证该实体已保存在数据库中。
接下来,当我刷新列出这些实体的 UI 时(我为此向数据库添加了一个新实体),新实体不包括在内,也没有从以下内容中检索到:
@Repository
@SuppressWarnings("unchecked")
public class PasswordDAOHibernate extends BaseDAOHibernate implements PasswordDAO {
@Override
public Collection<Password> getPasswords() {
Query query = session.createQuery("select ...");
return query.list();
}
这是界面:
public interface PasswordDAO {
Password getPassword(Integer id);
Collection<Password> getPasswords();
Collection<Password> getPasswords(PasswordSearchParameters params);
Collection<PasswordType> getPasswordTypes();
}
...
从 Controller 调用:
@Controller
public class PasswordsController extends BaseControllerHelper {
@Autowired
private PasswordDAOHibernate passwordDAO;
@RequestMapping("/passwords.htm")
public void passwords(Map model,
HttpServletRequest request) {
Collection<Password> passwords = passwordDAO.getPasswords();
model.put("passwords", passwords);
}
这是当前设置的配置: hibernate .cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.connection.url">jdbc:mysql://host:3306/server</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping class="com.crm.entity.User"></mapping>
<mapping class="com.crm.entity.Role"></mapping>
<mapping class="com.crm.entity.Property"></mapping>
<mapping class="com.crm.entity.Menu"></mapping>
<mapping class="com.crm.entity.Password"></mapping>
<mapping class="com.crm.entity.PasswordType"></mapping>
</session-factory>
</hibernate-configuration>
hibernate 工具.java
@Component
public class HibernateUtils {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close();
}
}
当我重新启动服务器应用程序时,新实体会显示在列表中。
是否存在某种我需要清除的隐式缓存?请注意,我在此阶段没有实现任何显式缓存。
最佳答案
问题出在您的 dao 上,它存在非常危险的缺陷。 Session
不是线程安全的,不应共享。它应该为每个操作打开(或者至少应该使用当前 session )。
你的 DAO 应该看起来像这样。
private final SessionFactory sessionFactory;
protected BaseDAOHibernate(SessionFactory sessionFactory) {
this.sessionFactory=sessionFactory;
}
protected Session getSession() {
return this.sessionFactory.getCurrentSession();
}
public void save(Object object) {
getCurrentSession().save(object);
}
现在您的特定 dao 应该重用 getSession
方法。
@Repository
@Transactional
public class PasswordDAOHibernate extends BaseDao implements PasswordDao {
@Autowired
public PasswordDAOHibernate(SessionFactory sessionFactory) {
super(sessionFactory);
}
@Override
public Collection<Password> getPasswords() {
return getSession.query("select ...", Password.class).list();
}
这样做时,您可能会遇到错误,指出由于没有事务无法找到 session (或类似的东西)。
要解决此问题,请使用 Spring Boot(以及一些手动配置)。
首先将 hibernate.connection
属性移动到您的 application.properties
并将它们从 hibernate.cfg.xml
中删除。
spring.datasource.url=jdbc:mysql://host:3306/server
spring.datasource.username=username
spring.datasource.password
现在 Spring 将为您创建一个 Datasource
。接下来删除您的 HibernateUtils
并使用 Springs LocalSessionFactoryBean
配置 SessionFactory
。
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
return factory;
}
您还需要合适的事务管理器
@Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
现在,由于在 Spring 中设置了所有内容,SessionFactory
和 @Transactional
的注入(inject),您将获得一个托管的 Session
,它将为您正确打开和关闭。
您的 Controller 也有缺陷,因为您应该注入(inject) PasswordDao
而不是具体类型(由于为交易创建代理,现在会失败)。
@Controller
public class PasswordsController extends BaseControllerHelper {
@Autowired
private PasswordDAO passwordDAO;
然而,尽管所有这些都可能有效,但我强烈建议使用 JPA 和 EntityManager
而不是 Session
和 SessionFactory
方法。
为此,删除 LocalSessionFactoryBean
和 HibernateTransactionManager
并将 hibernate.cfg.xml
的其余属性添加到 应用程序属性
。
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
在 spring.datasource
属性旁边就是您所需要的,您可以删除 hibernate.cfg.xml
文件。
现在不要使用 SessionFactory
,而是在您的 dao 中使用 EntityManager
。
public abstract class BaseDao {
@PersistenceContext
protected EntityManager em;
public void save(Object o) {
em.persist(o);
}
}
还有你的具体道。
@Repository
@Transactional
public PasswordJpaDao extends BaseDao implements PasswordDao {
@Override
public Collection<Password> getPasswords() {
return em.createQuery("select ...", Password.class).getResultList();
}
使用 JPA 时,您甚至可以放弃通用的 dao 方法和实现并使用 Spring Data JPA反而。你的整个 PasswordDao
看起来像
public interface PasswordDao extends JpaRepository<Password, Long> {}
所有 crud 功能(findAll
、findOne
、save
等)都是开箱即用的。创建查询非常简单,并且可以让您免于编写样板代码。
关于java - 如何在 Spring Boot 1.5.1 Hibernate 中防止隐式缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43015713/
我是一名优秀的程序员,十分优秀!