尝试使用@PostConstruct填充数据库时出现问题

时间:2016-03-06 20:34:37

标签: hibernate spring-mvc spring-security

我正在尝试通过Spring和Hibernate填充新创建的数据库模式。

我的@PostConstruct课程是:

@Component
public class DataInitializer {

    @Autowired
    private UserService userService;

    @Autowired
    private UserProfileService userProfileService;

    @PostConstruct
    public void firstLoad() {
        if (!(userProfileService.findAll().size() > 0)) {
            System.out.println("persistUserProfiles()");
            persistUserProfiles();
        } else {
            System.out.println("persistUserProfiles() NOT EXECUTED!");
        }   

        if (userService.findAll().size() == 0) {
            System.out.println("loadDefaultUser()");
            loadDefaultUser();
        } else {
            System.out.println("loadDefaultUser() NOT EXECUTED!");
        }
    }

    private void loadDefaultUser() {
        User user = new User();

        user.setSsoId("master");
        user.setPassword("$2a$10$Jv/rZ8wa7XiRY8XZ1lpIMeXL/Mol0Eda4XxHM7BE2Ui6BxpLZ95He");
        user.setFirstName("HRM");
        user.setLastName("Master User");
        user.setEmail("email@email");
        user.setState(State.ACTIVE.getState());
        user.setUserProfiles(loadDefaultUserProfiles());

        userService.save(user);
    }

    private Set<UserProfile> loadDefaultUserProfiles() {
        Set<UserProfile> userProfiles = new HashSet<UserProfile>();
        userProfiles.add(userProfileService.findByType(UserProfileType.USER.getUserProfileType()));
        userProfiles.add(userProfileService.findByType(UserProfileType.ADMIN.getUserProfileType()));
        userProfiles.add(userProfileService.findByType(UserProfileType.DBA.getUserProfileType()));

        return userProfiles;
    }

    private void persistUserProfiles() {
        UserProfile user = new    UserProfile(UserProfileType.USER.getUserProfileType());
        userProfileService.save(user);

        UserProfile admin = new UserProfile(UserProfileType.ADMIN.getUserProfileType());
        userProfileService.save(admin);

        UserProfile dba = new     UserProfile(UserProfileType.DBA.getUserProfileType());
    userProfileService.save(dba);
    }
}

但是在运行应用程序服务器时,我得到以下控制台输出和错误:

persistUserProfiles()
loadDefaultUser()
Mar 06, 2016 5:15:25 PM org.springframework.web.context.support.AnnotationConfigWebApplicationContext __refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataInitializer': Invocation of init method failed; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: b.c.m.h.m.UserProfile
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:480)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5075)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5591)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1574)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1564)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

输出明确说明问题出在UserProfile实体上,该实体定义为:

@Column(name="type", length=15, unique=true, nullable=false)
private String type = UserProfileType.USER.getUserProfileType();

// Constructor used only for initial data loading, not used after
public UserProfile() {
}

// Constructor used only for initial data loading, not used after
public UserProfile(String type) {
    super();
    this.type = type;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

定义UserProfileType的枚举是:

USER("USER"),
DBA("DBA"),
ADMIN("ADMIN");

String userProfileType;

private UserProfileType(String userProfileType){
    this.userProfileType = userProfileType;
}

public String getUserProfileType(){
    return userProfileType;
}

编辑:包含(希望)相关代码

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao dao;

    @Autowired
    private PasswordEncoder passwordEncoder;

    public void save(User user){
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        dao.save(user);
    }

    public void saveOrUpdate(User user) {
        // user.setPassword(passwordEncoder.encode(user.getPassword()));
        dao.saveOrUpdate(user);
    (...)
}

PasswordEncoder是org.springframework.security.crypto.password.PasswordEncoder

@Repository("userDao")
public class UserDaoImpl extends AbstractDao<String, User> implements UserDao {

    public void save(User user) {
        persist(user);
    }

    public void saveOrUpdate(User user) {
        saveOrUpdate(user);
    }
    (...)
}

处理会话的抽象类:

public abstract class AbstractDao<PK extends Serializable, T> {

    private final Class<T> persistentClass;

    @SuppressWarnings("unchecked")
    public AbstractDao(){
        this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
    }

    @Autowired
    private SessionFactory sessionFactory;

    protected Session getSession(){
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public T getByKey(PK key) {
        return (T) getSession().get(persistentClass, key);
    }

    public void persist(T entity) {
        getSession().persist(entity);
    }

    public void saveOrUpdate(T entity) {
        getSession().saveOrUpdate(entity);
    }
    (...)
}

发生了什么事?正在创建所有表,并且填充了user_profile表,但DataInitializer类在将用户配置文件分配给未被持久化的“主”用户时失败。

我在这里缺少什么?提前谢谢。

1 个答案:

答案 0 :(得分:0)

@Repository("userDao")
public class UserDaoImpl extends AbstractDao<String, User> implements UserDao {

public void save(User user) {
    persist(user);
}

public void saveOrUpdate(User user) {
    saveOrUpdate(user);
}
(...)

}

问题在于我引用自身的方法saveOrUpdate(User user)内部。

解决方案是:

public void saveOrUpdate(User user) {
    super.saveOrUpdate(user);
}