Страницы

Поиск по вопросам

Показаны сообщения с ярлыком hibernate. Показать все сообщения
Показаны сообщения с ярлыком hibernate. Показать все сообщения

суббота, 11 апреля 2020 г.

Spring RESTful Service

#java #spring #hibernate #rest

                    
Вообщем пишу веб-приложение на Spring. В приложение есть модель:

@Entity
@Table(name = "RSS_STREAM", uniqueConstraints = @UniqueConstraint(columnNames = {"link"}))
public class RssStream implements Serializable{

  @Id
  @GeneratedValue
  @Column
  private int id;

  @Column
  private String title;

  @Column
  @org.hibernate.validator.constraints.URL
  private String link;

  @Column
  @org.hibernate.validator.constraints.URL
  private String image;

  @Column
  private String description;

  @OneToMany(mappedBy = "rssStream", cascade = CascadeType.ALL)
  private Set feeds = new HashSet();
  // Тут еще геттеры и сеттеры, но не привожу их, т.к. они стандартные
}


Другая таблица:

@Entity
@Table(name = "RSS_FEED")
public class RssFeed {

  @Id
  @Column
  private String title;

  @Column
  @URL
  private String link;

  @Column
  private String description;

  @Column
  private String content;

  @Column
  @Temporal(TemporalType.TIMESTAMP)
  private Date pubDate;

  @Column
  @Temporal(TemporalType.TIMESTAMP)
  private Date updateDate;

  @ManyToOne
  @JoinColumn(name = "id")
  private RssStream rssStream;
}


Есть контроллер, который возвращает сериализованный объект RssStream, там есть все
поля. Но одно но, мне не нужно, что бы там было поле feeds. Если убрать геттеры и сеттеры,
то возникают проблемы при выборке из таблици RssFeed, что делать? Возможно ли как-то
исключить поля из сериализатора.
    


Ответы

Ответ 1



Вообщем в Jackson есть специальная аннотация: JsonIgnoreProperties. Она помогла решить проблему.

четверг, 9 апреля 2020 г.

Помогите написать правильно criteria в Hibernate

#java #hibernate

                    
Не могу понять как сделать сравнение в hibernate cruteria. Есть такой метод

@Override
    public List getPollForUpdate(IncomingSms incommingSMS) {
        Criteria criteria = getSession().createCriteria(PollEvent.class);
        criteria.add(Restrictions.eq("status", 0));
        criteria.add(Restrictions.eq("call.callingnum", incommingSMS.getSourceAddress()));
        return criteria.list();
    }


Он должен вернуть список объектов. Но ворачивает ошибку. ругается на criteria.add(Restrictions.eq("call.callingnum",
incommingSMS.getSourceAddress()));

В классе PollEvent есть поле call вот оно

@OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "CALL_ID", nullable = false)
    private Calls call;


а у него есть поле callingnum по которому  яи хочу сравнить

@Column(name = "CALLINGNUM", length = 15)
    private String callingnum;


Ошибка которую я получаю

could not resolve property: call.callingnum of: polls.entety.PollEvent

    


Ответы

Ответ 1



В этом случае необходимо создать либо вложенный criteria: Criteria criteria = getSession().createCriteria(PollEvent.class); criteria.add(Restrictions.eq("status", 0)); criteria.createCriteria("call") .add(Restrictions.eq("callingnum", incommingSMS.getSourceAddress())); либо использовать alias: Criteria criteria = getSession().createCriteria(PollEvent.class); criteria.add(Restrictions.eq("status", 0)); criteria.createAlias("call", "c"); criteria.add(Restrictions.eq("c.callingnum", incommingSMS.getSourceAddress())); Документация

пятница, 13 марта 2020 г.

Как организовать разработку приложения

#java #spring #hibernate #maven #веб_программирование


Здравствуйте!

Подскажите, пожалуйста, как организовать разработку веб-приложения, а именно, как
организовать взаимосвязь между применяемыми технологиями.

Я хочу создать веб-приложение по обмену вещами между пользователями. Приложение пишется
на Java + Spring MVC + Spring Security (для авторизации пользователя) + Hibernate с
использованием сборщика Maven, а в качестве СУБД используется HSQLDB. Для Представления
используется JSP. Сервер приложений - встроенный Jetty, не требующий внешнего веб-контейнера.

Вопросы:


Как сделать так, чтобы проект автоматически собирался и работал на любом ПК с предустановленными
JDK и Maven? Что для этого нужно сделать?
Что сделать, чтобы нужная схема данных автоматически создавалась и заполнялась начальными
данными при первом запуске веб-приложения?
Это должно происходить именно при первом запуске приложения, а не при каждом его
включении.
Расскажите поподробнее про то, как мне организовать доступ к HSQLDB из Hibernate,
учитывая требования (1 и 2) и как хранить/упаковать БД и СУБД исходя из этого.
Требуется также написать скрипт сборки проекта с помощью Maven и показать его исходники
заказчику. Что в данной ситуации будет скриптом сборки? Maven ведь декларативный сборщик.


Спасибо заранее!
    


Ответы

Ответ 1



Для этого достаточно использовать maven в качестве билд-системы. Тогда на любой машине с установленными maven и jdk можно будет выполнить mvn package и получить артефакт (вероятнее всего вы захотите zip-архив) с вашим продуктом. Вам скорее всего понадобятся maven-shade-plugin и/или maven-assembly-plugin. Автоматическое создание схемы можно доверить Hibernate (используя параметр hibernate.hbm2ddl.auto=update), но предпочтительнее делать это SQL-скриптом. Если планируются апдейты приложения и схемы данных, стоит задуматься об использовании средств версионирования схемы БД. Например, Flyway умеет проверять при старте версию схемы в БД последовательно накатывать необходимые миграции (SQL-скрипты, обновляющие схему) на БД и заливать исходные данные из XML. Файл данных БД можно хранить в директории приложения или за её пределами, например, в $HOME/.myapplication/ или в /var в Linux (%APPDATA%/myapplication в случае Windows). Хранение базы данных в отдельной рабочей директории даст ей больше шансов на выживание при удалении и переустановке вашей программы. Мавеновский pom.xml и будет скриптом сборки. Декларативным скриптом. Примерно все это можно получить "из коробки", используя Spring Boot. Просто идете на страницу http://start.spring.io, жмете Switch to the full version? заполняете форму и отмечаете флажками пункты: Web Security JPA HSQLDB и Generate project в конце. На выходе у вас будет архив с готовым скелетом приложения c maven-скриптом как раз под ваши нужды. Нужно будет доработать напильником: заменить Tomcat на Jetty и досыпать в зависимости Flyway, например.

воскресенье, 8 марта 2020 г.

Как передать свой объект из jsp в контроллер

#java #hibernate #jsp #spring_mvc #jstl


У меня есть User, в нем есть ссылка на Role, и например на странице editUser мне
надо собрать объект User в контроллер spring MVC(в параметры контроллера добавляю User
user), такие объекты как
name(String),email(String), age(int) собираются в User нормально, а чтобы добавить
туда Role мне надо редактируемого User'a достать из БД извлечь его роль и засетить
в новый объект User и только потом делать update в hibernate. 

Так вот вопрос можно ли как то spring'ом сразу User собрать вместе с Role из jsp
страницы?

Пробовал указать поле в верстке 

input type="hidden" name="role" value"${user.role}"


но тогда вообще контроллер не находит и редиректит на страницу 400.

P.S User добавляю из get-контроллера в jsp, тоесть переменные User можно достать в jsp
    


Ответы

Ответ 1



Как по мне, на уровне клиента это невозможно. Как вариант, тебе нужно сперва запросом отправить id нужного объекта, а потом используя id получить его. Я бы сделал бы это вот так html ... ... ... ... Внутри метода* .........@ModelAttribute("user") User user, @RequestParam("id") Integer id) { .... Role role = (Role) session.createQuery("from Role role where role.id=:id").setParameter("id", id).list().get(0); user.setRole(role); .... }

Ответ 2



input type="hidden" name="role" value"${user.role} Может вместо этого надо: input type="hidden" name="role" value="${user.role}"

пятница, 14 февраля 2020 г.

Для чего нужен Eager в связке с Lazy?

#java #hibernate


Был на собеседовании и задали такой вопрос:


  У нас есть Eager and Lazy, почему всегда не пользоваться Lazy? Для чего нужен Eager?
Ведь если Eager initialization потребляет больше памяти, из-за чего это может сказаться
на производительности..

    


Ответы

Ответ 1



Есть несколько случаев когда ранняя загрузка более предпочтительна: Иногда нам проще загрузить все данные сразу и работать с ними, нежели держать соединение до тех пор пока нам потребуется очередная порция данных Это может позволить так же сократить количество запросов - например, вместо двух один с join'ом. Порой это оказывается быстрее

четверг, 13 февраля 2020 г.

Hibernate - ошибка при создании таблицы

#java #spring #hibernate #java_ee


У меня есть модель User

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

// Пошаманить з User и настройками hibernate
@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private long id;

    @Column(nullable = false, length = 20)
    private String nickname;

    @Column(nullable = false, length = 20)
    private String password;

    @Column(length = 2)
    private String country;

    public User() {}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }
}


Создан контролер, репозиторий, но почему-то вылетает ошибка:

[2016-05-27 10:08:59,668] Artifact MessengerServer:war: Artifact is being deployed,
please wait...
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
27-May-2016 10:09:02.569 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.jpa.internal.util.LogHelper.logPersistenceUnitInformation
HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
27-May-2016 10:09:02.671 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.Version.logVersion
HHH000412: Hibernate Core {5.1.0.Final}
27-May-2016 10:09:02.674 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.cfg.Environment.
HHH000205: Loaded properties from resource hibernate.properties: {hibernate.show_sql=true,
hibernate.bytecode.use_reflection_optimizer=false, hibernate.hbm2ddl.auto=create, hibernate.dialet=org.hibernate.dialect.PostgreSQL9Dialect}
27-May-2016 10:09:02.674 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.cfg.Environment.buildBytecodeProvider
HHH000021: Bytecode provider name : javassist
27-May-2016 10:09:02.732 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.annotations.common.reflection.java.JavaReflectionManager.
HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
27-May-2016 10:09:03.206 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.dialect.Dialect.
HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL94Dialect
27-May-2016 10:09:03.366 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl.useContextualLobCreation
HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
27-May-2016 10:09:03.368 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.type.BasicTypeRegistry.register
HHH000270: Type registration [java.util.UUID] overrides previous : org.hibernate.type.UUIDBinaryType@48909093
Hibernate: drop table if exists room cascade
Hibernate: drop table if exists user cascade
27-May-2016 10:09:04.181 WARN [RMI TCP Connection(29)-127.0.0.1] org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl.handleException
GenerationTarget encountered exception accepting command : Unable to execute command
[drop table if exists user cascade]
 org.hibernate.tool.schema.spi.CommandAcceptanceException: Unable to execute command
[drop table if exists user cascade]
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:63)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:370)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:355)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:240)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:153)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:125)
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:111)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:137)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:64)
    at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:458)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:881)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:319)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:829)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4809)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5251)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1696)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:484)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:433)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
    at sun.reflect.GeneratedMethodAccessor80.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
Hibernate: create table room (id int8 not null, author varchar(255) not null, title
varchar(30) not null, primary key (id))
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    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)
Caused by: org.postgresql.util.PSQLException: ОШИБКА: ошибка синтаксиса (примерное
положение: "user")
  Позиция: 22
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:366)
    at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
    at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:51)
    ... 72 more

Hibernate: create table user (id int8 not null, country varchar(2), nickname varchar(20)
not null, password varchar(20) not null, primary key (id))
27-May-2016 10:09:04.241 WARN [RMI TCP Connection(29)-127.0.0.1] org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl.handleException
GenerationTarget encountered exception accepting command : Unable to execute command
[create table user (id int8 not null, country varchar(2), nickname varchar(20) not
null, password varchar(20) not null, primary key (id))]
 org.hibernate.tool.schema.spi.CommandAcceptanceException: Unable to execute command
[create table user (id int8 not null, country varchar(2), nickname varchar(20) not
null, password varchar(20) not null, primary key (id))]
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:63)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:423)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:408)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:310)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:165)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:134)
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:120)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:148)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:64)
    at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:458)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:881)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:319)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:829)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4809)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5251)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1696)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:484)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:433)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
    at sun.reflect.GeneratedMethodAccessor80.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    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)
Caused by: org.postgresql.util.PSQLException: ОШИБКА: ошибка синтаксиса (примерное
положение: "user")
  Позиция: 14
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:366)
    at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
    at org.apache.commons.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:51)
    ... 72 more

27-May-2016 10:09:04.247 INFO [RMI TCP Connection(29)-127.0.0.1] org.hibernate.tool.schema.internal.SchemaCreatorImpl.applyImportSources
HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@2850dd14'
[2016-05-27 10:09:05,739] Artifact MessengerServer:war: Artifact is deployed successfully
[2016-05-27 10:09:05,739] Artifact MessengerServer:war: Deploy took 6 071 milliseconds


У меня есть 1 таблица, и все работало, пока не создал вторую (не знаю, почему. Прилягаю
hibernate.properties :

hibernate.dialet = org.hibernate.dialect.PostgreSQL9Dialect
hibernate.show_sql = true

hibernate.hbm2ddl.auto = create


И db.properties : 

db.driver = org.postgresql.Driver
db.url = jdbc:postgresql://localhost:5432/messengerdb
db.username = postgres
db.password = root
db.entity.package = ua.samuliak.messenger.entity

db.initialSize = 30
db.minIdle = 30
db.maxIdle = 60
db.timeBetweenEvictionRunsMillis = 30000
db.minEvictableIdleTimeMillis = 60000
db.testOnBorrow = true
db.validationQuery = select version()


Spring я только начал изучать. Пока что не могу понять, как исправить ошибку.



UPDATE: Проблема решена! Не хотело создавать табличку с именем "user", заменил на
"client" и все хорошо. Но не понимаю, почему так 
    


Ответы

Ответ 1



user - зарезервированное слово в SQL. Его нужно экранировать: @Table(name="\"user\"")

воскресенье, 26 января 2020 г.

Как БЕЗОПАСНО сбрасывать кэш первого уровня?

#java #hibernate


Столкнулся с тем, что при редактировании одной из строк, мне при запросе возвращаются
старые данные.
Как в последствии выяснилось, он банально грузит его заново из кэша 1го уровня.
Стал перед нужными запросам сбрасывать его с помощью:

session.clear();


Но теперь возникает проблема при нескольких обновлениях одного и того же объекта:

org.hibernate.NonUniqueObjectException: a different object with the same identifier
value     was already associated with the session:


Подсобите, может надо по другому решать эту проблему?
    


Ответы

Ответ 1



Пришлось порыться... Суть в том что после .clear() ошибка срабатывает только при команде .update() или .saveOrUpdate(). Решение я нашел тут. Если коротко то эту команду надо заменить на .merge(Object o)

пятница, 24 января 2020 г.

Spring RESTful + hibernate многомодульный проект

#java #spring #hibernate #rest


Вопрос следующий!
Мне необходимо создать приложение, состоящее из нескольких модулей: 


authorization (модуль авторизации) 
main (основной модуль) 
directories (модуль со справочниками)
logging (модуль логирования)


В дальнейшем могут быть и другие модули. Каждый модуль представляет собой автономное
Spring Restful + hibernate приложение (war файлик). 

Модули должны взаимодействовать друг с другом. То есть, допустим, модуль main использует
справочники из модуля directories. 

Вопрос такой, какая существует практика взаимодействия между такими автономными модулями?
 Могу предположить, что модули общаются посредством rest запросов, но, тогда если,
допустим, мне потребуется получить в модуле main справочник городов city (из модуля
dictionaries), то мне в модуле main придется хранить класс-сущность City и так со всеми
сущностями.
    


Ответы

Ответ 1



Если Вы используете maven, опишите данные модули в pom файлах, кто от кого зависит при сборке и т.д. и используйте справочники из City при работе в main. Например основной pom.xml : 4.0.0 ru.group.example example-parent 0.1.0 pom example parent UTF-8 UTF-8 ... example-module1 example-module2 example-module3 org.apache.maven.wagon wagon-ssh-external org.apache.maven.wagon wagon-ssh org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 Затем файл pom.xml например module1 : ru.group.example example-parent 0.1.0 4.0.0 example-module1 war ru.group.example example-module2 ${project.version} module2, по аналогии с первым, у них будет общий перент и свои зависимости. Ну а дальше уже в коде импортируйтесь и используйте, свои классы методы и т.д.

Ответ 2



Если у вас несколько сервисов, то при rest комуникации им следует передавать не саму Entity -> City, а DTO -> CityDTO, это помогает избежать проблем с сериализацией. Наглядный пример различия DTO, POCO (POJO) и Value Object Создайте модуль "common", в котором будут находиться DTO, в том числе и CityDTO, а зетем добавьте на него зависимость модулям "main" (основной модуль) и "directories" (модуль со справочниками).

Проблема с получением данных из БД и с сохранением объектов в БД Oracle

#java #spring #oracle #hibernate #jackson


Мне надо получить список объектов file из базы данных через GET запрос.
Есть два класса:

File:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.persistence.*;
import java.io.IOException;
import java.util.Objects;

@Entity
@Table(name = "FILE_")
public class File {

    private Long id;
    private Long storageId;
    private String name;
    private String format;
    private Long size;
    private Storage storage;

    public File() {
    }

    @Id
    @SequenceGenerator(name = "F_SQ", sequenceName = "FILE_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "F_SQ")
    @Column(name = "FILE_ID")
    public Long getId() {
        return id;
    }

    @JsonIgnore
    //@JoinColumn(name = "STORAGE_ID_F")
    public Long getStorageId() {
        return storageId;
    }

    @Column(name = "NAME_FILE")
    public String getName() {
        return name;
    }

    @Column(name = "FORMAT_FILE")
    public String getFormat() {
        return format;
    }

    @Column(name = "SIZE_FILE")
    public Long getSize() {
        return size;
    }

    @JsonIgnore
    @ManyToOne(targetEntity = Storage.class, fetch = FetchType.LAZY)
    @JoinColumn(name = "STORAGE_ID_F")
    public Storage getStorage() {
        return storage;
    }

    @JsonCreator
    public static File createFromJson(String jsonString){

        ObjectMapper objectMapper = new ObjectMapper();

        File file = null;
        try {
            file = objectMapper.readValue(jsonString, File.class);
        }catch (IOException e){
            e.printStackTrace();
        }

        return file;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setStorageId(Long storageId) {
        this.storageId = storageId;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public void setSize(Long size) {
        this.size = size;
    }

    public void setStorage(Storage storage) {
        this.storage = storage;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        File file = (File) o;
        return Objects.equals(storageId, file.storageId) &&
                Objects.equals(name, file.name) &&
                Objects.equals(format, file.format) &&
                Objects.equals(size, file.size) &&
                Objects.equals(storage, file.storage);
    }

    @Override
    public int hashCode() {
        return Objects.hash(storageId, name, format, size, storage);
    }

    @Override
    public String toString() {
        return "File{" +
                "id=" + id +
                " name='" + name + '\'' +
                ", format='" + format + '\'' +
                ", size=" + size +
                ", storage=" + storage.getId() +
                '}';
    }
}


Storage:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.persistence.*;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

@Entity
@Table(name = "STORAGE_")
public class Storage {

    private Long id;
    private String formatsSupported;
    private String storageCountry;
    private Long storageSize;
    private List files;

    public Storage() {
    }

    @Id
    @SequenceGenerator(name = "ST_SQ", sequenceName = "STORAGE_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ST_SQ")
    @Column(name = "STORAGE_ID")
    public Long getId() {
        return id;
    }

    @Column(name = "FORMAT_SUPPORTED")
    public String getFormatsSupported() {
        return formatsSupported;
    }

    @Column(name = "COUNTRY_STORAGE")
    public String getStorageCountry() {
        return storageCountry;
    }

    @Column(name = "SIZE_STORAGE")
    public Long getStorageSize() {
        return storageSize;
    }

    @OneToMany(mappedBy = "storage", fetch = FetchType.LAZY, targetEntity = File.class)
    public List getFiles() {
        return files;
    }

    @JsonCreator
    public static Storage createFromJson(String jsonString){

        ObjectMapper objectMapper = new ObjectMapper();

        Storage storage = null;
        try {
            storage = objectMapper.readValue(jsonString, Storage.class);
        }catch (IOException e){
            e.printStackTrace();
        }

        return storage;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setFormatsSupported(String formatsSupported) {
        this.formatsSupported = formatsSupported;
    }

    public void setStorageCountry(String storageCountry) {
        this.storageCountry = storageCountry;
    }

    public void setStorageSize(Long storageSize) {
        this.storageSize = storageSize;
    }

    public void setFiles(List files) {
        this.files = files;
    }
}


В классе Controller метод с запросом на получение списка объектов из базы данных,
использую БД Oracle:

import com.fasterxml.jackson.databind.ObjectMapper;
import dz_spring_3.dao.FileDAO;
import dz_spring_3.dao.StorageDAO;
import dz_spring_3.model.File;
import dz_spring_3.model.Storage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;

@org.springframework.stereotype.Controller
public class Controller {

    @Autowired
    Service service;

    @Autowired
    StorageDAO storageDAO;

    @Autowired
    FileDAO fileDAO;

    @RequestMapping(method = RequestMethod.POST, value = "/saveFile", produces =
"text/plain")
    @ResponseBody
    public String saveFile(HttpServletRequest req)throws IOException {

        File file = mappingFile(req);

        if (file.getId() != null)
            return "Storage with id - " + file.getId() + " can`t be saved in DB.";

        file.setStorageId(storageDAO.findById(3L).getId());

        service.saveFile(file);

        return "File with id - " + file.getId() + " saved success.";
    }

    @RequestMapping(method = RequestMethod.GET, value = "/file", produces = "text/plain")
    @ResponseBody
    public String getAllFile(){

        return service.getAllFile().toString();
    }

    private File mappingFile(HttpServletRequest req)throws IOException {

        StringBuilder stringBuilder = new StringBuilder();

        try(BufferedReader reader = req.getReader()) {
            String line;

            while ((line = reader.readLine()) != null){
                System.out.println("Line in wile (mapping) - " + line);
                stringBuilder.append(line);
            }
        }

        ObjectMapper objectMapper = new ObjectMapper();

        String input = objectMapper.writeValueAsString(stringBuilder.toString());

        File file = objectMapper.convertValue(input, File.class);

        return file;
    }


Класс FileDAO: 

import dz_spring_3.model.File;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.NativeQuery;

import javax.persistence.TypedQuery;
import java.util.List;

public class FileDAO extends GeneralDAO {

    private static final String SQL_GET_ALL_FILES = "SELECT * FROM FILE_";
    private static final String SQL_GET_BY_ID_FILE = "SELECT * FROM FILE_ WHERE FILE_ID
= ?";

    @SuppressWarnings("unchecked")
    public List getAllFile(){
        List files;

        try(Session session = createSessionFactory().openSession()) {

            NativeQuery query = session.createNativeQuery(SQL_GET_ALL_FILES);
            files = query.addEntity(File.class).list();

        }catch (HibernateException e){
            System.err.println(e.getMessage());
            throw new HibernateException("Operation failed");
        }
        return files;
    }

    public File saveFile(File file) {

        Transaction tr = null;
        try(Session session = createSessionFactory().openSession()) {
            tr = session.getTransaction();
            tr.begin();

            session.save(file);

            tr.commit();
        }catch (HibernateException e){
            System.err.println("Save is failed.");
            System.err.println(e.getMessage());
            if (tr != null)
                tr.rollback();
        }

        return file;
    }

    public void updateFile(File file){

        Transaction transaction = null;
        try(Session session = createSessionFactory().openSession()) {
            transaction = session.getTransaction();
            transaction.begin();

            session.update(file);

            transaction.commit();
        }
        catch (HibernateException e){

            if (transaction != null)
                transaction.rollback();

            System.err.println(e.getMessage());
            throw new HibernateException("Operation failed.");
        }
    }

    public void deleteFile(Long id){

        Transaction transaction = null;
        try(Session session = createSessionFactory().openSession()) {
            transaction = session.getTransaction();
            transaction.begin();

            session.delete(findById(id));

            transaction.commit();
        }
        catch (HibernateException e){

            if (transaction != null)
                transaction.rollback();

            System.err.println(e.getMessage());
            throw new HibernateException("Operation failed.");
        }
    }

    @SuppressWarnings("unchecked")
    public File findById(Long id){

        File file;

        try(Session session = createSessionFactory().openSession()) {

            NativeQuery query = session.createNativeQuery(SQL_GET_BY_ID_FILE);
            if (getSingleResult(query, id) == null){
                file = null;
            }
            else
                file = (File) query.addEntity(File.class).setParameter(1, id).getSingleResult();

        }catch (HibernateException e){
            System.err.println(e.getMessage());
            throw new HibernateException("Operation failed.");
        }
        return file;
    }

    private  T getSingleResult(TypedQuery query, Long id){
        query.setMaxResults(1);

        List list = query.setParameter(1, id).getResultList();

        if (list == null || list.isEmpty()){

            return null;
        }
        return list.get(0);
    }
}


После того, как запускаю сервер Tomcatи делаю запрос 
http://localhost:8080/fileпадает несколько ошибок, вот стектрэйс:

org.springframework.web.util.NestedServletException: Request processing failed; nested
exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException:
could not execute query
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
        org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause

    javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException:
could not execute query
        org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
        org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
        org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1423)
        dz_spring_3.dao.FileDAO.getAllFile(FileDAO.java:24)
        dz_spring_3.Service.getAllFile(Service.java:56)
        dz_spring_3.Controller.getAllFile(Controller.java:111)
        sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        java.lang.reflect.Method.invoke(Method.java:498)
        org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
        org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
        org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
        org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause

    org.hibernate.exception.GenericJDBCException: could not execute query
        org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
        org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
        org.hibernate.loader.Loader.doList(Loader.java:2695)
        org.hibernate.loader.Loader.doList(Loader.java:2675)
        org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2507)
        org.hibernate.loader.Loader.list(Loader.java:2502)
        org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
        org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2161)
        org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1016)
        org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:152)
        org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
        dz_spring_3.dao.FileDAO.getAllFile(FileDAO.java:24)
        dz_spring_3.Service.getAllFile(Service.java:56)
        dz_spring_3.Controller.getAllFile(Controller.java:111)
        sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        java.lang.reflect.Method.invoke(Method.java:498)
        org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
        org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
        org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
        org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Root Cause

    java.sql.SQLException: Недопустимое имя столбца
        oracle.jdbc.driver.OracleStatement.getColumnIndex(OracleStatement.java:3965)
        oracle.jdbc.driver.InsensitiveScrollableResultSet.findColumn(InsensitiveScrollableResultSet.java:299)
        oracle.jdbc.driver.GeneratedResultSet.getLong(GeneratedResultSet.java:1361)
        org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$2.doExtract(BigIntTypeDescriptor.java:63)
        org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
        org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:261)
        org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)
        org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:247)
        org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:333)
        org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2854)
        org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1747)
        org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1673)
        org.hibernate.loader.Loader.getRow(Loader.java:1562)
        org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:732)
        org.hibernate.loader.Loader.processResultSet(Loader.java:991)
        org.hibernate.loader.Loader.doQuery(Loader.java:949)
        org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
        org.hibernate.loader.Loader.doList(Loader.java:2692)
        org.hibernate.loader.Loader.doList(Loader.java:2675)
        org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2507)
        org.hibernate.loader.Loader.list(Loader.java:2502)
        org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
        org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2161)
        org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1016)
        org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:152)
        org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
        dz_spring_3.dao.FileDAO.getAllFile(FileDAO.java:24)
        dz_spring_3.Service.getAllFile(Service.java:56)
        dz_spring_3.Controller.getAllFile(Controller.java:111)
        sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        java.lang.reflect.Method.invoke(Method.java:498)
        org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
        org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
        org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
        org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
        org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    Note The full stack trace of the root cause is available in the server logs.


Я так понимаю, эта проблема идёт из-за поля storageId, когда его убираю совсем, то
данные из базы считываются. Но это поле мне надо для того, чтобы сохраняемому в базу
объекту file просетить id хранилища storage в котором находится этот файл. Ну и при
попытке сохранить file в базу через Post запрос, тоже падает ошибка:

org.springframework.web.util.NestedServletException: Request processing failed; nested
exception is javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException:
Unable to release JDBC Connection
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

Root Cause

javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException:
Unable to release JDBC Connection
org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
    org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
    org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1423)
    org.hibernate.query.Query.getResultList(Query.java:146)
    dz_spring_3.dao.StorageDAO.getSingleResult(StorageDAO.java:119)
    dz_spring_3.dao.StorageDAO.findById(StorageDAO.java:103)
    dz_spring_3.Controller.saveFile(Controller.java:98)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:498)
    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

Root Cause

org.hibernate.exception.JDBCConnectionException:
Unable to release JDBC Connection
    org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)
    org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.releaseConnection(LogicalConnectionManagedImpl.java:199)
    org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.afterTransaction(LogicalConnectionManagedImpl.java:162)
    org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.afterTransaction(JdbcCoordinatorImpl.java:288)
    org.hibernate.internal.SessionImpl.afterOperation(SessionImpl.java:557)
    org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2168)
    org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1016)
    org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:152)
    org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
    org.hibernate.query.Query.getResultList(Query.java:146)
    dz_spring_3.dao.StorageDAO.getSingleResult(StorageDAO.java:119)
    dz_spring_3.dao.StorageDAO.findById(StorageDAO.java:103)
    dz_spring_3.Controller.saveFile(Controller.java:98)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:498)
    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

Root Cause

java.sql.SQLRecoverableException: Закрытое соединение




Файл hibernate.cfg.xml:





Что-то делаю не правильно, а вот что именно не могу понять.
Прошу подсказать или объяснить, как мне получить список объектов и сохранять объекты
file в базу данных.
    


Ответы

Ответ 1



Чтобы исправить NullPointerException в методе File.toString() нужно переписать метод @Override public String toString() { return "File{" + "id=" + id + " name='" + name + '\'' + ", format='" + format + '\'' + ", size=" + size + ", storage=" + (storage != null?storage.getId():"null") + "}"; } Потом вы перепутали сериализацию с десериализацией, нужно писать что-то типа ObjectMapper objectMapper = new ObjectMapper(); String input = stringBuilder.toString(); File file = objectMapper.readValue(input, File.class); но storage у вас неверно задан, т.е. вы можете использовать String input in (mapping) - "{\t\"name\":\"File02\",\t\"format\":\"doc\",\t\"size\":\"200\",\t\"storage\":{\"id\":\"3\"}}" Потом у вас проблема с соединениями, что соединения не закрываются как следует, и с каждым запросом создается новое количество соединений. Некоторые соединения продолжают использоваться после того как они были закрыты. Для того, чтобы исправить эту ошибку нужно закрывать фактор сессий (если вы его постоянно создаете, правда непонятно зачем, но это уже ваше дело). Например можно использовать try(SessionFactory factory = createSessionFactory();Session session = factory.openSession()) {

Ответ 2



Но это поле мне надо для того, чтобы сохраняемому в базу объекту file просетить id хранилища storage в котором находится этот файл Внешний ключ для storage как самостоятельная сущность в File не нужен; в коде эта связь выражается через JoinColumn("STORAGE_ID_F"): @JsonIgnore @ManyToOne(targetEntity = Storage.class, fetch = FetchType.LAZY) @JoinColumn(name = "STORAGE_ID_F") public Storage getStorage() { return storage; } Поле в БД добавится на основе данной конфигурации. Соответственно, в PUT необходимо в File добавлять экземпляр Storage через setStorage(), а не его идентификатор через setStorageId().

воскресенье, 12 января 2020 г.

Возможно ли в Hibernate при связывании таблиц (@OneToMany @ManyToOne) получить вместо объекта только поле Id?

#java #spring #hibernate


Суть проблемы в том что у меня Класс связанный в древовидную структуру по принципу
предок/потомки, но когда я получаю объект у которого есть предок и потомки из БД вытягиваются
не только эти объекты, но и объекты связанные с предком и потомками, а мне достаточно
было бы получать только Id предка и списки List Id потомков, возможно ли связывать
таблицы и получать только их Id, не вытягивая из БД весь остальной фарш?

сейчас так:

@Entity
@Table(name="testpage")
public class TestPage {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long Id;
    @Column(unique=true,nullable=false)
    private String Name;
    private int position;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn()
    @JoinTable(name="parent_testpage",joinColumns=@JoinColumn(name="page_id", referencedColumnName="id"),
    inverseJoinColumns=@JoinColumn(name="parent_id", referencedColumnName="id"))
    private TestPage Parent;
    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name="parent_testpage",joinColumns=@JoinColumn(name="parent_id", referencedColumnName="id"),
    inverseJoinColumns=@JoinColumn(name="page_id", referencedColumnName="id"))
    private List Child;

    ...getters and setters
}


хотелось бы так:

@Entity
@Table(name="testpage")
public class TestPage {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long Id;
    @Column(unique=true,nullable=false)
    private String Name;
    private int position;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn()
    @JoinTable(name="parent_testpage",joinColumns=@JoinColumn(name="page_id", referencedColumnName="id"),
    inverseJoinColumns=@JoinColumn(name="parent_id", referencedColumnName="id"))
    private long ParentId;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name="parent_testpage",joinColumns=@JoinColumn(name="parent_id", referencedColumnName="id"),
    inverseJoinColumns=@JoinColumn(name="page_id", referencedColumnName="id"))
    private List ChildIds;

...getters and setters

}

    


Ответы

Ответ 1



Сразу оговорюсь, что это касается JPA. У Hibernate есть ещё какие-то свои родные механизмы - я их не знаю. Только отдельный запрос, как говорит Ruslan Nekura, поможет получить id child-ов. (Но есть ещё один вариант. О нём чуть ниже) Не работает JPA по-другому. Не ссылается он на отдельные поля других entity. Только на объект целиком. parent_Id - это поле в того же самого entity. Оно может быть использовано и так и сяк и даже одновременно: ... @JoinTable(name="parent_testpage", joinColumns=@JoinColumn(name="page_id", referencedColumnName="id"), inverseJoinColumns=@JoinColumn(name="parent_id", referencedColumnName="id")) private TestPage Parent; @Column(name="parent_id", insertable=false, updatable=false) private Long parentId; ... Если используются одновременно, то одно отображение обязательно отметить как "только для чтения". В примере это parentId с параметрами аннотации insertable, updatable = false. Со списком child-ов, как уже сказано выше, такой номер не пройдёт. И вот ещё одна метода. Можно сделать view в базе с полями parent_id и child_id. CREATE VIEW view_child_ids (long parent_id, long child_id) AS SELECT parent_id, id FROM testpage WHERE parent_id IS NOT NULL; Отобразить эту view в виде Basic ElementCollection: ... @ElementCollection @CollectionTable(name = "view_child_ids", joinColumns=@JoinColumn(name = "parent_id")) @Column(name = "child_id") private List childIds; ... Для этой view ещё надо будет всяких правил/триггеров определить на случай каскадных удаления/изменения. Есть в этом свои недостатки, но не буду их упоминать. Они проявляются при определённых обстоятельствах. Может Вам повезёт, ведь никто не знает всей Вашей задумки. Сам предпочитаю запросы. Радикальный вариант - уйти с JPA/Hibernate на альтернативный способ доступа к данным, работающий на других принципах. Active-record какой-нибудь.

Ответ 2



В hibernate есть такой параметр как lazy, он то и отвечает за неполную загрузку. В xml он указывается параметр: lazy="true" Пример: Можно отмечать как всю таблицу, так определенный столбец. В аннотациях вот так: @Basic(fetch = FetchType.LAZY) Другими словами объекты с такой пометкой будут загружены ТОЛЬКО когда вы обратитесь к ним напрямую! P.S. Хотя мне вот тоже зависимости не нужно загружать (точнее очень редко), так я в обще зависимости не стал указывать. Он мне всегда одни id дает, а я уж ручками загружу, если в этом возникнет необходимость.

Ответ 3



У вас в коде @ManyToOne(fetch = FetchType.EAGER), то есть вы явно просите hibernate вытягивать вообще все до разрешенного в конфигурации уровня вложений hibernate.max_fetch_depth при абсолютно любом запросе. Попробуйте указать FetchType.LAZY, а в случае, когда явно нужны связанные потомки использовать NamedQuery типа такого @NamedQuery(name = TestPage.GET_PAGE_WITH_CHILD, query = "select distinct p " + "from TestPage p left join fetch p.Child " + "where p.Parent = :parent") В этом случае вы получите объект с явно инициализированными зависимостями первого уровня, у которых в свою очередь зависимости будут заменены прокси. Ну и отвечая на вопрос в том виде, в котором вы его поставили. Да, можно получить Long[] id, если запросить только его через NamedQuery как-нибудь так @NamedQuery(name = Person.GET_CHILD_ID_BY_PARENT, query = "select p.id from TestPage p where p.parent = :parent) И маленькая ремарка в конце. По стандарту имена переменных, полей и методов пишутся с маленькой буквы, а имена классов - с большой.

пятница, 10 января 2020 г.

Использование criteria из JPA

#java #hibernate #jpa


В новом Hibernate использование Criteria является Deprecated. Как я могу заменить
такой код с использованием org.hibernate.Criteria:

Criteria criteria = session.createCriteria(Role.class);
long id = ((Role) criteria.add(Restrictions.eq("name", name)).uniqueResult()).getId();


на его эквивалент с использованием javax.persistence.criteria.CriteriaBuilder из JPA ?
    


Ответы

Ответ 1



em - экземпляр EntityManager. public Long query(String name) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Role.class); Root root = cq.from(Role.class); cq.where(cb.equal(root.get("name"), cb.parameter(String.class, "name"))); // cq.distinct(true); Query q = em.createQuery(cq); q.setParameter("name", name); List result = q.getResultList(); if (result.size() > 0) { return result.get(0).getId(); } return null; }

Ответ 2



Ну вот когда есть что скопипастить (спасибо, Виктор) public Long query(String name) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Role.class); Root root = cq.from(Role.class); cq.where(cb.equal(root.get("name"), cb.parameter(String.class, "name"))); try { // Тут возможно надо делать приведение типов, // либо вызывать вариант метода, в котором указывается тип возвращаемого параметра // em.createQuery(cq, Role.class)... // либо и так сойдёт return em.createQuery(cq).setParameter("name", name).getSingleResult().getId(); } catch (NoResultException ex) { return null; } } или public Long query(String name) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Role.class); Root root = cq.from(Role.class); cq.where(cb.equal(root.get("name"), cb.parameter(String.class, "name"))); List roles = em.createQuery(cq).setParameter("name", name).getResultList(); return roles.isEmpty() ? null : roles.get(0).getId(); } Ну то есть вариант Виктора без лишнего distinct и местами собранный в одну строку за счёт fluent-а, широко применяемого в JPA API. Если используете генерацию статичной метамодели, тогда root.get("name") заменяется на root.get(Role_.name). Типа безопасно. Чо. Иначе на фига Вам вообще criteria, когда есть текстовый JPQL, а ещё лучше SQL?

понедельник, 6 января 2020 г.

JpaRepository + Hibernate + OneToMany вылетает LazyInitializationException

#java #spring #hibernate #jpa #spring_data


реализую отношение one-to-many по этому туториалу а также этому спринговому туториалу.
Я НЕ использую сессии и прочий hibernate напрямую, я использую JpaRepository и аннотации
JPA. Есть объекты Owner (one) & Book (many):

первая таблица:

@Entity
@Table(name = "owners")
public class Owner implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "owner_id", nullable = false, unique = true)
    private Long id;

    @Column(name = "owner_name", nullable = false)
    private String name;

    @OneToMany(fetch = FetchType.LAZY,mappedBy = "owner")
    private Set books= new HashSet<>(0);

    public Worker() {
    }
}


вторая таблица: 

@Entity
@Table(name = "books")
public class Book implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "book_id", unique = true, nullable = false)
    private Long id;

    @Column(name = "book_name", nullable = false, unique = true)
    private String name;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner_id")
    private Owner owner;

    public Task() {
    }
}


слой репозиториев стандартный, без реализации:

public  interface OwnerRepository extends JpaRepository {}

public  interface BookRepository extends JpaRepository {}


Owner service: (book service такой же)

@Service
@Transactional
public class OwnerServiceImpl implements OwnerService {

    @Autowired
    private OwnerRepository ownerRepository;

    @Override
    public Owner create(Owner owner) {return ownerRepository.save(owner);}

    @Override
    public Owner read(Long id) {return ownerRepository.findOne(id);}

    @Override
    public List readAll() {return ownerRepository.findAll();}

    @Override
    public void delete(Owner owner) {ownerRepository.delete(owner);}

}


Создав два класса service, я захотел протестить их. Создал несколько Owner,Book ну
и пытаюсь связать их как указано здесь, т.е. добавляю в объектe Owner в Set новую книжку,
а в объект Book обновляю ссылку на Owner. Сохраняю в репозиторий сначала Owner, затем
Book. Затем пытаюсь прочитать Owner из репозитория, а во время обращения к полю выдаёт 


  unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException'
exception.


может я вообще неправильно работаю с репозиторием и JPA? как нужно сохранять/обновлять
ссылки в сущностях?

===UPDATE===

мне кажется я решил проблему, использовав @NamedEntityGraph & @EntityGraph.
Я аннотировал Owner 

@NamedEntityGraph(name = "Owner.books",
    attributeNodes = @NamedAttributeNode("books"))


Но в интерфейсе репозитория пришлось переопределить стандартные методы:

@Override
@EntityGraph(value = "Owner.books", type = EntityGraph.EntityGraphType.LOAD)
List findAll();


@Override
@EntityGraph(value = "Owner.books", type = EntityGraph.EntityGraphType.LOAD)
OwnerfindOne(Long aLong);


Тоже самое сделал с Book. Когда я делаю запрос из репозитория Owner на считывание
объекта, всё загружается нормально - ссылки в Set ссылаются на объекты Book. 
Но когда я делаю запрос к Book репозиторию - объект Book имеет ссылку на Owner, НО
в этом внутреннем Owner ссылки на дополнительные книги бросают LazyInitException. Почему?
ссылки просматриваю в Idea на брек поинте.
    


Ответы

Ответ 1



У вас стоит fetch = FetchType.LAZY это значит, что хибернейт не будет инициализировать эти поля пока вы к ним не обратитесь. Но т.к. вы обращаетесь к этим полям за пределами транзакционных методов, он не может это сделать и выкидывает ошибку. Чтобы этого избежать надо, что метод, который обращается к этим полям был с аннотацей Transactional. В вашем случае это EntitiesServicesTest.ooops(). Либо можно немного изменить реализацию OwnerServiceImpl.read(). Сделать такое: @Override public Owner read(Long id) { Owner owner = ownerRepository.findOne(id); owner.getBooks().iterator(); return owner; } Или как предложили в комментариях: Hibernate.initialize(owner.getBooks()); Это хак, но он заставит хибернейт инициировать коллекцию. НО! Возможно это не всегда надо и тогда надо выбрать первый вариант и отталкиваться от здравого смысла, смотреть, где надо навешивать аннотацию, а где нет.

Ответ 2



Стоит также упомянуть, что fetch type по дефолту как раз LAZY. Я для решения проблемы поставил fetch = FetchType.EAGER и всё заработало.

суббота, 4 января 2020 г.

Сессии и DAO классы в Hibernate

#java #база_данных #hibernate #orm


Здравствуйте.

Есть маленький проектик работающий с БД. В качестве ORM решения выбран Hibernate 4. 

Попутно обуздывая фреймворк, создал классы сущностей, связал аннотациями, использовал
DAO pattern. Но: в имплементации ДАО классов в каждом изменяющем БД методе сессия открывалась
и закрывалась прямо в методе (как и в этой туториал ссылочке http://javaxblog.ru/article/java-hibernate-1/).
Пример

Session session = null;
        try {
            session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            // Здесь добавляю, обновляю или удаляю
            // ...
            session.getTransaction().commit();
        } catch (Exception e) {
            // Обрабатываю
            // rollback()
        } finally {
            // Закрываю
            if (session != null && session.isOpen()) {
                session.close();
            }
        }


Но что-то подсказывает, что это как-то, мягко говоря, не правильно. 
Порыв немного интернет, наткнулся на статейку (https://developer.jboss.org/wiki/GenericDataAccessObjects),
где говорится, что ДАО имплементации не должны создавать сессию внутри, а на неё нужно
лишь ссылаться. Если я правильно понял, ДАО имплементаций не должно волновать создание
сессий. 


  You could also use constructor injection. How you set the Session and what scope
this Session has is of no concern to the actual DAO implementation. A DAO should not
control transactions or the Session scope.


Интересует вопрос опытных разработчиков: 
создавать ли сессию один раз на всё приложение и просто в сеттере давать ссылочку
ДАО классам (при этом сессию не закрывать), или же в каждом методе ДАО класса создавать
и закрывать сессию? 
    


Ответы

Ответ 1



Жаль, что автор не нашёл время сам ответить на свой вопрос. Хоть я ни разу не опытный разработчик, попробую ответить на основании информации, которую нашёл в сети на текущий день. На многих ресурсах рекомендуют использовать Hibernate в связке со Spring. Мне не нравится этот совет тем, что вводится лишняя "сущность". Человек учится пользоваться отвёрткой, а ему хотят всучить шуруповёрт. Да, вроде бы шуруповёрт круче, но и отвёрткой уметь пользоваться тоже не будет лишним. Ручное открытие/закрытие сессии. В первую очередь напрашивается такая структура взаимодействия: слой DAO содержит только основные (CRUD - create, read, update, delete) операции взаимодействия с базой данных; в бизнес-слой выносятся операции, которые можно (и нужно) объединять в транзакции. Выглядит DAO-класс примерно так: public class ItemDAOImpl implements ItemDAO { private Session session; public ItemDAOImpl(Session session) { this.session = session; } @Override public Item get(long id) { return session.get(Item.class, id, LockMode.PESSIMISTIC_READ); } @Override public long create(Item item) { return (Long) session.save(item); } @Override public void update(Item item) { session.update(item); } @Override public Item delete(long id) { Item item = session.byId(Item.class).load(id); session.delete(item); return item; } } Сессия session создаётся в бизнес-слое и передаётся в конструктор DAO: public class AdminServiceImpl extends PersonServiceImpl implements AdminService { SessionFactory sessionFactory; public AdminServiceImpl(SessionFactory sessionFactory){ this.sessionFactory = sessionFactory; } @Override public long createItem(Item item) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); long id = dao.create(item); transaction.commit(); return id; } catch (HibernateException | NoResultException e) { throw new DBException(e); } } @Override public void updateItem(Item item) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); dao.update(item); transaction.commit(); } catch (HibernateException | NoResultException e) { throw new DBException(e); } } @Override public void deleteItem(long id) throws DBException { try (Session session = sessionFactory.openSession()){ Transaction transaction = session.beginTransaction(); ItemDAO dao = new ItemDAOImpl(session); Item item = dao.delete(id); transaction.commit(); } catch (HibernateException | NoResultException | IllegalArgumentException e) { throw new DBException(e); } } } Недостаток метода очевиден - при большой нагрузке должен активно работать сборщик мусора, чтобы освобождать память от DAO- и сервисных объектов. Это осталось за кадром, но подразумевается, что также должен создаваться объект сервисного класса AdminServiceImpl. В конструкторе этот объект получает ссылку на объект типа SessionFactory. Стратегия открытия сессии Чтобы избавиться от постоянного создания dao - и сервисных объектов, нужен механизм создания сессии или получения текущей сессии в каждом из этих объектов независимо друг от друга. И тут на помощь приходят стратегии открытия-закрытия сессии. Рекомендую эту статью к прочтению. Допустим, что выбираем стратегию ManagedSessionContext - каждому потоку по отдельной сессии. Тогда для получения сессии можно будет использовать Session session = sessionFactory.getCurrentSession(); Увы, сразу это не заработает. Чтобы заработало, нужно в hibernate.cfg.xml прописать thread. Или второй способ - в конфигурацию hibernate добавить свойство configuration.setProperty("hibernate.current_session_context_class", "thread"); Уже знакомый DAO-класс будет теперь выглядеть так: public class ItemDAOImpl implements ItemDAO { ItemDAOImpl() { } @Override public Item get(long id) { return DBService.getSessionFactory() .getCurrentSession() .get(Item.class, id, LockMode.PESSIMISTIC_READ); } @Override public long create(Item item) { return (Long) DBService.getSessionFactory() .getCurrentSession() .save(item); } @Override public void update(Item item) { DBService.getSessionFactory().getCurrentSession() .update(item); } @Override public Item delete(long id) { Session session = DBService.getSessionFactory().getCurrentSession(); Item item = session.byId(Item.class).load(id); session.delete(item); return item; } } Здесь DBService - абстрактный класс, содержащий ссылку на объект SessionFactory. Так выглядит функция getSessionFactory(): public static SessionFactory getSessionFactory(){ return sessionFactory; } А вот и переделанный сервисный класс: public class AdminServiceImpl extends PersonServiceImpl implements AdminService { AdminServiceImpl() { } @Override public long createItem(Item item) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); long id = dao.create(item); transaction.commit(); return id; } catch (HibernateException | NoResultException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } @Override public void updateItem(Item item) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); dao.update(item); transaction.commit(); } catch (HibernateException | NoResultException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } @Override public void deleteItem(long id) throws DBException { Transaction transaction = DBService.getTransaction(); try { ItemDAO dao = DaoFactory.getItemDAO(); Item item = dao.delete(id); transaction.commit(); } catch (HibernateException | NoResultException | IllegalArgumentException | IllegalStateException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } } Вот используемые функции из DBService: public static Transaction getTransaction(){ Session session = DBService.getSessionFactory().getCurrentSession(); Transaction transaction = DBService.getSessionFactory().getCurrentSession().getTransaction(); if (!transaction.isActive()) { transaction = session.beginTransaction(); } return transaction; } public static void transactionRollback(Transaction transaction){ if (transaction.getStatus() == TransactionStatus.ACTIVE || transaction.getStatus() == TransactionStatus.MARKED_ROLLBACK) { transaction.rollback(); } } А вот класс DaoFactory для получения инстанса ItemDAO: public abstract class DaoFactory { private static ItemDAO itemDAO = new ItemDAOImpl(); public static ItemDAO getItemDAO() { return itemDAO; } } Собственно, на этом, думаю, всё. Для тех, кто хочет пощупать код, вот ссылки на github: - ручное управление сессией; - управление при помощи ManagedSessionContext.

Ответ 2



когда слишком много операций на вставку или обновление необходимо делать, то кадрый раз открытие и закрытие сесии отнимет много времени в совокупности. По этой причине данные действия можно позволить решить выше. private Session currentSession; private Transaction currentTransaction; public Session openCurrentSession() { currentSession = HibernateUtil.HibernateUtil.getSessionFactory().openSession(); return currentSession; } public Session openCurrentSessionwithTransaction() { currentSession = HibernateUtil.getSessionFactory().openSession(); currentTransaction = currentSession.beginTransaction(); return currentSession; } public void closeCurrentSession() { currentSession.close(); } public void closeCurrentSessionwithTransaction() { currentTransaction.commit(); currentSession.close(); } public void update(Object o) { this.currentSession.update(o); } таким образом, Вы сами решаете, когда открывать сессию и когда закрывать.

Ответ 3



Использование ссылки на SessionFactory внутри реализации DAO и создание сессии на каждый вызов дао методов. Для массивных изменений рекомендуется batch update.

среда, 25 декабря 2019 г.

Сохранение цен в логах

#java #hibernate #jpa #интернет_магазин #ecommerce


Есть таблица товаров (Goods). У каждого товара есть цена. При создании заказа (Order)
к нему прикрепляются товары с помощью дополнительной таблицы Goods__Order. При этом
после заказа цены товаров в заказе не должны меняться, даже если они изменились в таблице
Goods.

Один из вариантов - сохранять цену в таблицу Goods__Order. Но количество полей, которые
не должны меняться, возможно, станет больше, и поэтому не хочется их все переносить
в эту таблицу + вариант не очень универсальный.

Второй вариант, как мне кажется, можно логировать изменения в таблице Goods в таблицу
Goods_audit, которая будет содержать изменения полей + номер версии (revision number).
Это доступно через Hibernate Envers. Но тогда в таблицу Goods_Order нужно будет вносить
id товара + номер версии + я не нашел примеров, что так делают.

Какой вариант будет лучше? Учитывая, огромное количество интернет-магазинов, наверное
уже есть более-менее известное решение для этого. Да и во вариантах на php никакого
Hibernate Envers нет.
    


Ответы

Ответ 1



Заказ не является объектом бухгалтерского учета, это объект процессов логистики и взаимоотношения с клиентами. Однозначных рекомендаций по логистике и CRM не существует, правильная постановка таких процессов является ноухау организации. Пока заказ не оплачен, он является по сути предложением клиенту и объектом любой переоценки. В магазине могут действовать правила расчета цены отдельного товара для клиента с учетом скидок (иногда и надбавок) - скидка по промокоду, скидка за объем заказа (суммарный по всем товарным позициям заказа), персональная скидка клиента (например - за историю заказов, либо скидка отдельным категориям клиентов), и т.д. За время, когда заказ ожидает оплаты, может стартовать кампания по стимулированию спроса - на отдельные товары/группы начинает действовать значительная скидка, которая отменяет другие скидки (промокод, песональные и т.д.). После того, как заказ оплачен (тем более - если исполнен), все текущие условия - базовая цена, скидки, условия доставки и пр. - должны быть зафиксированы и не подлежать дальнейшим изменениям. В развитых eComm платформах типа Magento текущие цены ведутся в отдельных объектах - прайс-листах, могут настраиваться правила перерасчета цен (скажем, в зависимости от валютных котировок для импортных товаров), ведется история изменения прайс-листов. Правила перерасчета неоплаченных заказов также могут настраиваться. Так должно быть, а реализуется ли это в конкретной eComm и как - зависит от платформы. Если сами пишете платформу - посоветуйтесь с отделом продаж :-)

Ответ 2



Топорный вариант В таблицу Order(заказ)пишите цену на момент заказа добавить поле price(цена). Создать таблицу price_history[ид товара,номер ревизии,цена, дата и прочее если надо] и вносить каждое изменения цены туда. В таблице Goods хранится всего лишь ид ревизии цены.

javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread

#java #spring #hibernate #spring_mvc #jpa


GenericDao.java:

@Repository
public abstract class GenericDao implements GeneralDao {

    private Class className;

    public GenericDao(Class className) {
        this.className = className;
    }

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    @Override
    public void add(T object) {
        try {
            getEntityManager().persist(object);
        } catch (HibernateException e) {
            throw new DaoException(ErrorMessage.ADD_ENTITY_FAIL, e);
        }
    }

    @Override
    public void update(T object) {
        try {
            getEntityManager().merge(object);
        } catch (HibernateException e) {
            throw new DaoException(ErrorMessage.UPDATE_ENTITY_FAIL, e);
        }
    }

    @Override
    public void remove(T object) {
        try {
            getEntityManager().remove(object);
        } catch (HibernateException e) {
            throw new DaoException(ErrorMessage.REMOVE_ENTITY_FAIL, e);
        }
    }

    @Override
    public T getById(int id) {
        try {
            return getEntityManager().find(this.className, id);
        } catch (HibernateException e) {
            throw new DaoException(ErrorMessage.GET_BY_ID_ENTITY_FAIL, e);
        }
    }

    public abstract List getAll() throws DaoException;

}


GenericService.java

@Service
public abstract class GenericService implements GeneralService {
    private static Logger logger = Logger.getLogger(GenericService.class);

    @Autowired
    private GenericDao dao;

    @Transactional
    @Override
    public void add(T object) throws ServiceException {
        try {
           dao.add(object);
        } catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Transactional
    @Override
    public void update(T object) throws ServiceException {
        try {
            dao.update(object);
        } catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Transactional
    @Override
    public void remove(T object) throws ServiceException {
        try {
            dao.remove(object);
        } catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Transactional(readOnly = true)
    @Override
    public T getById(int id) throws ServiceException {
        try {
            return dao.getById(id);
        } catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
    }

    @Transactional(readOnly = true)
    @Override
    public List getAll() throws ServiceException {
        try {
            return dao.getAll();
        } catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
    }

}


UserServiceImpl.java:

@Service
public class UserServiceImpl extends GenericService implements UserService {
    private static Logger logger = Logger.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;

    @Transactional
    @Override
    public String checkUser(String userLogin, String userPassword) throws ServiceException {
        String namePage = "errorAuthorization";
        List userList;
        try {
           userList = userDao.getByLoginAndPassword(userLogin, userPassword);
        }  catch (DaoException e) {
            logger.debug(e);
            throw new ServiceException(e.getMessage());
        }
        if(userList.size() != 0) {
            return UserRoleChecker.defineUserPage(userList.get(0));
        }
        return namePage;
    }

    @Transactional
    @Override
    public void addUser(String userLogin, String userPassword, String userMail) throws
ServiceException {
        Role role = new Role(0L, RoleType.USER);
        User user = new User(0L, userLogin, userPassword, userMail, role);
        add(user);
    }

}


UserController.java:

@Controller
public class UserController {
    private static String className = UserController.class.getName();
    private static Logger logger = Logger.getLogger(UserController.class.getName());

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/check_user", method = RequestMethod.POST)
    public ModelAndView authorizationUser(HttpServletRequest request, HttpServletResponse
response) {
        ModelAndView modelAndView = new ModelAndView();
        String returnPage;
        try {
            returnPage = userService.checkUser(request.getParameter(RequestParameter.USER_LOGIN),
request.getParameter(RequestParameter.USER_PASSWORD));
        } catch (ServiceException e) {
            logger.debug(e);
            returnPage = ErrorHandler.returnErrorPage(e.getMessage(), className);
        }
        modelAndView.setViewName(returnPage);
        return modelAndView;
    }

    @RequestMapping(value = "/add_user", method = RequestMethod.POST)
    public ModelAndView registrationUser(HttpServletRequest request, HttpServletResponse
response) {
        ModelAndView modelAndView = new ModelAndView();
        String returnPage = Page.SUCCESSFUL_REGISTRATION;
        try {
            userService.addUser(request.getParameter(RequestParameter.USER_LOGIN),
request.getParameter(RequestParameter.USER_PASSWORD), request.getParameter(RequestParameter.USER_MAIL));
        }  catch (ServiceException e) {
            logger.debug(e);
           returnPage = ErrorHandler.returnErrorPage(e.getMessage(), className);
        }
        modelAndView.setViewName(returnPage);
        return modelAndView;
    }

}


root-context.xml:




    

    
    
    

    
        
        
        
        
        
        
    

    
        
        
        
            
                
                
                
            
        
        
            
                org.hibernate.dialect.MySQLDialect
                true
                true
                2
                true
                update
            
        
        
    

    

    

    

    
        
        
        
    




logs:

org.springframework.web.servlet.FrameworkServlet 2017-05-10 22:23:59,107 DEBUG -
Could not complete request
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction
available for current thread - cannot reliably process 'persist' call
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:282)
    at com.sun.proxy.$Proxy27.persist(Unknown Source)
    at by.netcracker.artemyev.dao.GenericDao.add(GenericDao.java:35)
    at by.netcracker.artemyev.service.GenericService.add(GenericService.java:24)
    at by.netcracker.artemyev.service.impl.UserServiceImpl.addUser(UserServiceImpl.java:48)
    at by.netcracker.artemyev.web.UserController.registrationUser(UserController.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:475)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:495)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:767)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1354)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)


Почему возникает эта ошибка и как её исправить?
    


Ответы

Ответ 1



Проблема в том, что spring не строит прокси-объект поверх UserServiceImpl, а внедряет его напрямую в UserController, что видно из твоего исключения. Причины, я полагаю, в том, что твой root-context.xml относится к контексту всего приложения, т.е. инициализируется через ContextLoaderListener. Внутри указанного контекста UserServiceImpl имеет транзакционность. Однако, у тебя также имеется некая конфигурация (тут лучше бы приложить web.xml) относящаяся к DispatcherServlet, в которой инициализируется UserController и как раз нет tx:annotation-driven. Соответственно в UserController попадет чистый бин, а не его прокси. Быстро решить данную проблему можно убрав @Service с самого класса UserServiceImpl и определив его в root-context.xml

Ответ 2



У меня была подобная проблема. Исправил так - в контексте для сервлета в аннотации component-scan указал не корневое пространство имен, а конкретно то, которое хранит Rest-контроллер src/main/webapp/spring/appServlet-context.xml После данных изменений рутовый контекс рулил бинами сервисов и проблем не было.