Приветствую всех! У меня как у новичка в программировании возникли трудности в освоении новых технологий. Переходя с голой Jdbc + сервлеты на Hibernate+Spring, я столкнулся , как мне казалось, с целым айсбергом(google уже весь фиолетовый), и самая большая сложность - правильно соединить все составляющие. Конечно, как говорят, я мог воспользоваться Spring Boot-ом, и он бы решил многие мои проблемы, но все-таки я очень хочу разбираться в том, что я делаю(ведь я уже и так на высоком уровне абстракции). В общем вопрос мой комплексный, и надеюсь на вашу помощь, ребята:
Для начала пару вопросов по конфигурационному файлу, вот мой
mvc-spring-dispatcher.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mydbtest"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.springapp.mvc"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
Я очень долго искал лучшее для меня решение, хотел, чтобы Spring инкапсулировал все, и реализацией Jpa был именно Hibernate. Это сейчас еще, если так можно выразиться, актуальное решение, либо есть какой-то более эффективный вариант?
Получается же ведь, что именно это настройка вобрала в себе persistence.xml?
DriverManagerDataSource, я как понимаю тут происходит настройка пула-соединений, т.е фактически маршрут для entityManager до БД, а именно тут происходит настройка количества подключений либо их длительности? Дальше фактически идет настройка провайдера Jpa и все как в persistence.xml, но зачем вводить бин JpaTransactionManager? Что именно он мне дает? Настройка @Transactional? Но разве, если я не буду включать этот бин в конфигурацию и просто оставлю , то разве менеджером транзакций не будет и так прописанный Jpa?
Так же у меня не хочет проходить транзакция(Ниже будет приведен список задействованных классов ):
Person:import javax.persistence.*;
@Entity
@Table(name = "person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "id" )
private Integer id;
@Column(name = "name", length = 40 )
private String name;
@Column(name = "email", length = 100 )
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", email=" + email + "]";
}
}
PersonDao:
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.springapp.mvc.Entities.Person;
import org.springframework.stereotype.Repository;
@Repository("personDao")
public class PersonDao {
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void insert(Person person) {
entityManager.persist(person);
}
public List<Person> selectAll() {
Query query = entityManager.createQuery("");
List<Person> persons = (List<Person>) query.getResultList();
return persons;
}
}
PersonService:package com.springapp.mvc.Service;
import java.util.List;
import com.springapp.mvc.DAO.PersonDao;
import com.springapp.mvc.Entities.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class PersonService {
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
@Autowired
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Transactional(propagation = Propagation.REQUIRED)
public void addPerson(Person person) {
getPersonDao().insert(person);
}
public List<Person> fetchAllPersons() {
return getPersonDao().selectAll();
}
}
Часть Контроллера :@RequestMapping(value = "/superData", method = RequestMethod.POST , produces= MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PeopleEntity> peopleEntity(@RequestBody Person transform) {
System.out.println(transform);
PersonService service=new PersonService();
service.addPerson(transform);
PeopleEntity peopleEntity = new PeopleEntity();
peopleEntity.setFirstName("John");
peopleEntity.setLastName("Dorian");
return new ResponseEntity<PeopleEntity>(peopleEntity, HttpStatus.OK);
}
Вот моя таблица: CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
А вот эту он генерирует автоматически, хотелось бы узнать причину:CREATE TABLE `hibernate_sequences` (
`sequence_name` varchar(255) NOT NULL,
`next_val` bigint(20) DEFAULT NULL,
PRIMARY KEY (`sequence_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Вот в чем суть:
До контроллера доходят параметры: name и email, но дальше случаются следующие вещи:
1) При трансформации информации в класс Person, имени и емэйлу присваиваются соответствующие значения, но id=null. Так же правильно делать? Ведь это значение я оставляю на генерацию в таблице :
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
И в данном случае оно должно проставить id само в соответствии со счетчиком в таблице?
2) Почему если я не определяю в
@Column(name = "email", length = 100 )
длину, то оно изменяет саму таблицу, и делает максимальные значение по 255, если hibernate.hbm2ddl.auto=update? Или этот параметр на это значение не влияет?
3) Почему создается дополнительная таблица(
hibernate_sequences), хотя я нигде этого не указываю?
4) Почему не выпадает никакого эксепшена, если транзакция не прошла?
Дальше вопросы про аннотации:
@Repository
- она как расширенный @Component, только с расширенными возможностями: выбрасывает свои специальные эксепшены, имеет значение как логический компонент для разработчика(Т.е человек будет видеть, что это класс DAO слоя). Для чего служит значение указанное в аннотации, в данном случае
@Repository("personDao")
?
@PersistenceContext
- как я понял, она автоматически инжектит EntityManager, который я выбрал и настроил тут в бинах: org.springframework.orm.jpa.JpaTransactionManager? Т.е это убирает шаблонные действия по созданию менеджера для транзакций, начиная от createEntityManager, до getTranssaction().begin()?
@Transaction
- активируется и в свою очередь комитит все транзакции а потом закрывает? Опционально может и откат делать, в случае неудачи? Что значит
(propagation = Propagation.REQUIRED)? Я конечно нашел несколько объяснений, но без примера, не совсем понятно как оно работает и вообще для чего.
И последний вопрос: в слое Dao, когда я хочу выбрать всех пользователей я создаю запрос :
Query query = entityManager.createQuery("from Person"), это язык hql, но почему-то idea не нравится этот запрос, хотя я видел полно примеров где этот способ работал;
Заранее прошу прощения, что вопросов такое множество, и может было бы лучше разделить их на несколько небольших, но мне показался такой комплексный подход наиболее подходящим.