V
V
Valentine2016-02-19 02:10:39
Java
Valentine, 2016-02-19 02:10:39

Clarification in Spring+Hibernate(JPA) configuration. Assistance in setting up transactions. Why don't they pass?

Welcome all! As a beginner in programming, I had difficulties in mastering new technologies. Moving from bare Jdbc + servlets to Hibernate + Spring, I faced, as it seemed to me, with a whole iceberg (google is already all purple), and the biggest difficulty is to correctly connect all the components. Of course, as they say, I could use Spring Boot, and it would solve many of my problems, but still I really want to understand what I'm doing (after all, I'm already at a high level of abstraction). In general, my question is complex, and I hope for your help guys:
First, a couple of questions about the configuration file, here is my 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"/>

I was looking for the best solution for me for a very long time, I wanted Spring to encapsulate everything, and Hibernate was the implementation of Jpa. Is it still, if I may say so, an up-to-date solution, or is there some more effective option?
It turns out, after all, what exactly is this setting that has absorbed persistence.xml?
DriverManagerDataSource, as I understand it, the connection pool is configured here, that is, in fact, the route for the entityManager to the database, and it is here that the number of connections or their duration is configured? Further, the Jpa provider is actually configured and everything is the same as in persistence.xml, but why introduce the JpaTransactionManager bean? What exactly does he give me? Setting @Transactional? But unless I don’t include this bean in the configuration and just leave it, won’t Jpa already be the transaction manager?
I also do not want to go through a transaction (The list of involved classes will be given below):
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;
    }
}

Person Service:
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();
    }
}

Controller Part :
@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);
    }

Here is my table:
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

But it generates this one automatically, I would like to know the reason:
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

Here's the bottom line:
The controller receives the parameters: name and email, but then the following things happen:
1) When the information is transformed into the Person class, the corresponding values ​​are assigned to the name and email, but id=null. Is it the right way to do it? After all, I leave this value for generation in the table:
@Id
    @GeneratedValue(strategy = GenerationType.TABLE)
And in this case, it should put down the id itself in accordance with the counter in the table?
2) Why, if I don't define the length, then it changes the table itself, and makes the maximum value 255 if hibernate.hbm2ddl.auto=update? Or does this parameter not affect this value? 3) Why is an additional table created ( hibernate_sequences ), even though I don't specify it anywhere? 4) Why is no exception thrown if the transaction fails? More questions about annotations:@Column(name = "email", length = 100 )

@Repository- it is like an extended @Component, only with extended features: it throws out its own special events, it matters as a logical component for the developer (i.e. a person will see that this is a DAO layer class). What is the purpose of the value specified in the annotation, in this case @Repository("personDao")?
@PersistenceContext- as I understand it, it automatically injects the EntityManager, which I chose and configured here in the beans: org.springframework.orm.jpa.JpaTransactionManager? That is, it removes the template actions for creating a manager for transactions, starting from createEntityManager, to getTranssaction().begin()?
@Transaction- is activated and in turn commits all transactions and then closes? Optionally, can you do a rollback, in case of failure? What does (propagation = Propagation.REQUIRED) mean?Of course, I found several explanations, but without an example, it is not entirely clear how it works and in general for what.
And the last question: in the Dao layer, when I want to select all users, I create a query:
Query query = entityManager.createQuery("from Person"), this is hql language, but for some reason idea doesn't like this query, although I saw a lot of examples where this method worked;
I apologize in advance that there are so many questions, and it might be better to divide them into several small ones, but such an integrated approach seemed to me the most appropriate.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Eugene, 2016-02-19
@Waynes

I won’t tell you for all of Odessa, but in Siberia it is believed that
1) @GeneratedValue(strategy = GenerationType.TABLE)- says that you need to use a table to generate PK. Not the table onto which the entity is mapped, but just a table. This is where the hibernate_sequences table comes from. And it occurs because of hibernate.hbm2ddl.auto=update.
2) About the length of the column, this is again due to hibernate.hbm2ddl.auto=update.
3) @Transactionsays the method will be transactional. What does it mean. This means that the method call will be wrapped in a proxy object that will have a session, and when all nested methods are called, this session will be the same, and when the method ends, the transaction will be closed.
4) propagation = Propagation.REQUIRED- this means that the presence of a session when calling the method is mandatory, if it is not there, then hibernate will try to create it.
5) Transaction rollback (roughly speaking rollbak) occurs, by default, only in case of occurrence RuntimeException, how to manage it is written in the documentation for hibernate.
6) the value in the annotation @Repository("personDao")specifies the name of the bean.
Now, according to the classics, something needs to be advised. I advise you not to use hibernate.hbm2ddl.auto=update. Better look towards liquibase for database state management.
And read introductory tutorials on Spring, understand how IoC works in Spring, how AOP works in Spring, how Spring manages beans. And then everything will become clear to you.
Go for it, good luck to you!

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question