Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Hibernate Spring Integration @Transactional: Tutorial, Examples, FAQs & Interview Tips

Spring + Hibernate Integration

Spring integrates seamlessly with Hibernate. The most common approach is to use Spring Data JPA with Hibernate as the JPA provider. Spring manages the SessionFactory/EntityManagerFactory, transactions, and exception translation automatically.

Spring Boot + Hibernate Configuration
# Spring Boot auto-configures Hibernate as JPA provider
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA/Hibernate settings
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

# Connection pool (HikariCP - Spring Boot default)
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000

# Hibernate statistics (for debugging)
spring.jpa.properties.hibernate.generate_statistics=false
<dependencies>
    <!-- Spring Boot Starter Data JPA (includes Hibernate) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

@Transactional with Spring

@Transactional Service Layer
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional // All methods are transactional by default
public class OrderService {

    private final OrderRepository orderRepository;
    private final UserRepository userRepository;
    private final ProductRepository productRepository;

    public OrderService(OrderRepository orderRepository,
                        UserRepository userRepository,
                        ProductRepository productRepository) {
        this.orderRepository = orderRepository;
        this.userRepository  = userRepository;
        this.productRepository = productRepository;
    }

    // Read-only transaction (optimization)
    @Transactional(readOnly = true)
    public List<Order> getUserOrders(Long userId) {
        return orderRepository.findByUserId(userId);
    }

    // Write transaction - rolls back on any RuntimeException
    @Transactional
    public Order placeOrder(Long userId, Long productId, int quantity) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found"));

        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("Product not found"));

        if (product.getStock() < quantity) {
            throw new RuntimeException("Insufficient stock"); // Triggers rollback
        }

        // Deduct stock
        product.setStock(product.getStock() - quantity);
        productRepository.save(product);

        // Create order
        Order order = new Order();
        order.setUser(user);
        order.setProduct(product);
        order.setQuantity(quantity);
        order.setTotal(product.getPrice() * quantity);

        return orderRepository.save(order);
        // Transaction commits here if no exception
    }

    // Rollback only on specific exceptions
    @Transactional(rollbackFor = {Exception.class},
                   noRollbackFor = {IllegalArgumentException.class})
    public void processPayment(Long orderId) throws Exception {
        // ...
    }
}

Using EntityManager Directly

EntityManager in Spring
import jakarta.persistence.*;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class CustomUserRepository {

    // Spring injects EntityManager (thread-safe proxy)
    @PersistenceContext
    private EntityManager em;

    public User findById(Long id) {
        return em.find(User.class, id);
    }

    public List<User> findByRole(String role) {
        return em.createQuery("FROM User u WHERE u.role = :role", User.class)
                .setParameter("role", role)
                .getResultList();
    }

    public User save(User user) {
        if (user.getId() == null) {
            em.persist(user);
            return user;
        } else {
            return em.merge(user);
        }
    }

    public void delete(Long id) {
        User user = em.find(User.class, id);
        if (user != null) em.remove(user);
    }

    // Access Hibernate Session from EntityManager
    public void hibernateSpecificOperation(Long id) {
        org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
        User user = session.get(User.class, id);
        // Use Hibernate-specific features
    }
}

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.