For information on using non-default Datasource settings, please refer to howto.data-access.configure-two-datasources
This is a proof-of-concept test.
application.yaml : remove hibernate: hbm2ddl:
AnagSourceConfiguration.java : The main changes are all in this file.
AnagRepositoriesConfig.java : The file is not required.
Database - Docker
docker run \
--name my-mysql-temp \
-e MYSQL_ROOT_PASSWORD=Passw0rd! \
-e MYSQL_DATABASE=demodb \
-e MYSQL_USER=demouser \
-e MYSQL_PASSWORD=Passw0rd! \
-p 3306:3306 \
-d \
mysql:8.0.43-debian
Project Tree
demo-mysql-jpa_ST
├── pom.xml
├── README.txt
└── src
└── main
├── resources
│ └── application.yaml <-- Change
└── java
└── com
└── example
├── DemoApplication.java
├── config
│ └── AnagSourceConfiguration.java <-- Change
├── entity
│ └── anag
│ └── Student.java
├── repo
│ └── anag
│ └── StudentRepository.java
├── service
│ └── anag
│ └── StudentService.java
└── controller
└── anag
└── StudentController.java
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo-mysql-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-mysql-jpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yaml
- remove
hibernate: hbm2ddl:
spring:
application:
name: demo-mysql-jpa
datasource:
url: jdbc:mysql://localhost:3306/firstdb
username: firstuser
password: Passw0rd1
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
anag:
datasource:
url: jdbc:mysql://localhost:3306/demodb
driver-class-name: com.mysql.cj.jdbc.Driver
username: demouser
password: Passw0rd!
jpa:
hibernate:
ddl-auto: update
show-sql: true
DemoApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
AnagSourceConfiguration.java
The main changes are all in this file.
package com.example.config;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
//@Configuration
//@ConditionalOnProperty(prefix = "spring.anag.datasource", name = "url")
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(
basePackages = "com.example.repo.anag",
entityManagerFactoryRef = "anagEntityManagerFactory",
transactionManagerRef = "anagTransactionManager"
)
public class AnagSourceConfiguration {
/*
@Value("${spring.anag.hibernate.hbm2ddl.auto:validate}")
private String hibernateHbm2ddlAuto;
@Value("${hibernate.dialect}")
private String hibernateDialect;
*/
/*
@Bean(name = "anagDataSource")
@ConfigurationProperties("spring.anag.datasource")
public DataSource anagDataSource() {return DataSourceBuilder.create().build();
}
*/
// 1- DataSourceProperties binding YAML
@Bean
@ConfigurationProperties("spring.anag.datasource")
public DataSourceProperties anagDataSourceProperties() {
return new DataSourceProperties();
}
// 2- create HikariDataSource
@Bean
@ConfigurationProperties("anag.datasource.configuration")
public HikariDataSource anagDataSource(
@Qualifier("anagDataSourceProperties") DataSourceProperties properties) {
return properties.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
/*
@Bean(name = "anagEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean anagEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(anagDataSource());
em.setPackagesToScan("com.example.entity.anag");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendoimport com.zaxxer.hikari.HikariDataSource;
final HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", hibernateHbm2ddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
em.setJpaPropertyMap(properties);
return em;
}
*/
// 3- EntityManagerFactory binding DataSource + JPA properties
@Bean(name = "anagEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean anagEntityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("anagDataSource") DataSource anagDataSource) {
return builder
.dataSource(anagDataSource)
.packages("com.example.entity.anag") // entity package
.persistenceUnit("anag")
.build();
}
/*
@Bean(name = "anagTransactionManager")
public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory anagEntityManagerFactory) {
return new JpaTransactionManager(anagEntityManagerFactory);
}
*/
// 4- TransactionManager
@Bean(name = "anagTransactionManager")
public PlatformTransactionManager anagTransactionManager(
@Qualifier("anagEntityManagerFactory") EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
}
The AnagRepositoriesConfig.java file is not required.
Student.java
package com.example.entity.anag;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(length = 100, nullable = false)
private String name;
@Column(name = "birth_date")
private LocalDate birthDate;
@Column(length = 100)
private String email;
@Column(length = 2)
private String grade;
@Column(name = "enrollment_date")
private LocalDate enrollmentDate;
}
StudentRepository.java
package com.example.repo.anag;
import com.example.entity.anag.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface StudentRepository extends JpaRepository<Student, Integer> {
List<Student> findByName(String name);
}
StudentService.java
package com.example.service.anag;
import com.example.entity.anag.Student;
import com.example.repo.anag.StudentRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@Transactional(transactionManager = "anagTransactionManager")
public class StudentService {
private final StudentRepository repo;
public List<Student> listAll() {
return repo.findAll();
}
public Optional<Student> findById(Integer id) {
return repo.findById(id);
}
public List<Student> findByName(String name) {
return repo.findByName(name);
}
public Student create(Student student) {
return repo.save(student);
}
public Student update(Integer id, Student student) {
return repo.findById(id)
.map(s -> {
s.setName(student.getName());
s.setBirthDate(student.getBirthDate());
s.setEmail(student.getEmail());
s.setGrade(student.getGrade());
s.setEnrollmentDate(student.getEnrollmentDate());
return repo.save(s);
})
.orElseThrow(() -> new RuntimeException("Student ID not found: " + id));
}
public void delete(Integer id) {
repo.deleteById(id);
}
}
StudentController.java
package com.example.controller.anag;
import com.example.entity.anag.Student;
import com.example.service.anag.StudentService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/anag/students")
public class StudentController {
private final StudentService service;
@GetMapping
public List<Student> listAll() {
return service.listAll();
}
@GetMapping("/{id}")
public Student findById(@PathVariable Integer id) {
return service.findById(id).orElse(null);
}
@GetMapping("/name/{name}")
public List<Student> findByName(@PathVariable String name) {
return service.findByName(name);
}
// CREATE
@PostMapping
public Student create(@RequestBody Student student) {
return service.create(student);
}
// UPDATE
@PutMapping("/{id}")
public Student update(@PathVariable Integer id, @RequestBody Student student) {
return service.update(id, student);
}
// DELETE
@DeleteMapping("/{id}")
public void delete(@PathVariable Integer id) {
service.delete(id);
}
}
Build
mvn clean package
Run
java -jar target/app.jar
Test
Create
curl -X POST http://localhost:8080/api/anag/students \
-H "Content-Type: application/json" \
-d '{
"name": "Alice",
"birthDate": "2005-05-20",
"email": "[email protected]",
"grade": "A",
"enrollmentDate": "2023-09-01"
}'
List All
curl http://localhost:8080/api/anag/students
Update
curl -X PUT http://localhost:8080/api/anag/students/1 \
-H "Content-Type: application/json" \
-d '{
"name": "AliceUpdated",
"birthDate": "2005-05-20",
"email": "[email protected]",
"grade": "A",
"enrollmentDate": "2023-09-01"
}'
Read Id: 1
curl http://localhost:8080/api/anag/students/1
Read Name is AliceUpdated
curl http://localhost:8080/api/anag/students/name/AliceUpdated
Delete Id: 1
curl -X DELETE http://localhost:8080/api/anag/students/1