Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRoute selected Spring Data repositories to a read replica by giving them a marker annotation and scanning them with a second @EnableJpaRepositories configuration. Keep the unmarked repositories on the primary EntityManagerFactory; bind the marked repositories to a read-only data source and its own EntityManagerFactory. This is explicit repository selection—it is not automatic routing from @Transactional(readOnly = true).
The architecture: two repository groups, two EntityManagers
The pattern in Emmanouil Gkatziouras’s October 10, 2019 tutorial creates two persistence paths:
| Repository group | Selection rule | EntityManagerFactory | Data source | Intended use | Freshness |
|---|---|---|---|---|---|
| Ordinary repositories | Included by the primary scan and excluded when marked @ReadOnlyRepository |
Primary entityManagerFactory |
Primary/write database | Queries, inserts, updates and deletes | Authoritative primary state |
| Read repositories | Included only when annotated @ReadOnlyRepository |
Secondary readEntityManagerFactory |
Configured by spring.datasource.readUrl |
Read operations that can tolerate replica lag | May be behind the primary after a write |
The annotation is a component-scanning selector. It does not grant database permissions, prove that a replica is healthy, or prevent a driver from accepting a write.
1. Define a repository interface with no mutation API
Use Spring Data’s base Repository interface when you want to expose only explicitly declared methods. The sample read repository exposes findAll() and deliberately does not inherit save, delete or other CRUD mutation methods.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
package com.example.employee;
import org.springframework.data.repository.Repository;
import java.util.List;
public interface ReadEmployeeRepository extends Repository<Employee, Long> {
List<Employee> findAll();
}
This narrows what application code can call through that interface. It is still not a substitute for database-level privileges: the read connection should be granted only the permissions your deployment requires, and the application should test that policy separately.
2. Add a runtime marker annotation
Make the marker visible to Spring’s repository scanner at runtime and target it at repository interfaces.
package com.example.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadOnlyRepository {
}
Annotate only repositories intended for the replica:
@ReadOnlyRepository
public interface ReadEmployeeRepository extends Repository<Employee, Long> {
List<Employee> findAll();
}
3. Configure the primary repository scan
The primary configuration scans the application’s repository package, excludes interfaces carrying @ReadOnlyRepository, and points the resulting repositories at the primary factory. Mark the primary data source and factory as @Primary so unqualified injections resolve to the write path.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Rank #2
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.employee",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = ReadOnlyRepository.class
),
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager"
)
public class PrimaryRepositoryConfiguration {
// Define the primary DataSource, entityManagerFactory and transactionManager.
// Mark the DataSource and EntityManagerFactory @Primary.
}
Use the actual package containing your ordinary repositories. If the package is too broad, the two scans can overlap or pick up repositories that belong on the replica.
4. Configure the read repository scan
A second scan includes only repositories carrying the marker and binds them to the read factory and its transaction manager.
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.employee",
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = ReadOnlyRepository.class
),
entityManagerFactoryRef = "readEntityManagerFactory",
transactionManagerRef = "readTransactionManager"
)
public class ReadRepositoryConfiguration {
// Define the read DataSource, readEntityManagerFactory and readTransactionManager.
}
Both scans may use the same base package because their include and exclude filters partition the interfaces. Separate packages are also possible, but the selection rule must remain unambiguous.
5. Supply a second data source and EntityManagerFactory
The read factory must be built from a data source that points at the replica. The tutorial uses a separate spring.datasource.readUrl setting for that connection. Bind the same JPA entity packages and vendor properties needed by the primary factory, then create a distinct transaction manager for the read factory.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
spring.datasource.url=jdbc:postgresql://primary.example/people
spring.datasource.readUrl=jdbc:postgresql://replica.example/people
The exact bean definitions depend on your Spring Boot and Spring Data versions. Verify current APIs, bean names, driver settings, dialect configuration, and transaction-manager wiring against the versions running in your application; the 2019 tutorial does not pin a complete Boot, Java, JDBC-driver or PostgreSQL version set.
6. Inject the repository that matches the operation
Keep write workflows on the ordinary repository and use the marked repository for replica-tolerant reads.
@RestController
class EmployeeController {
private final EmployeeRepository employeeRepository;
private final ReadEmployeeRepository readEmployeeRepository;
EmployeeController(EmployeeRepository employeeRepository,
ReadEmployeeRepository readEmployeeRepository) {
this.employeeRepository = employeeRepository;
this.readEmployeeRepository = readEmployeeRepository;
}
@PostMapping("/employee")
Employee create(@RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@GetMapping("/employee/read")
List<Employee> readFromReplica() {
return readEmployeeRepository.findAll();
}
}
Choose the read repository only when the caller can accept replica consistency. A read immediately following a write may need the primary repository instead.
Repository routing is different from transaction read-only mode
Spring Data JPA’s current transactionality reference (identified as Spring Data JPA 4.1.1 and accessed September 30, 2026) states that inherited CRUD read operations default to readOnly=true, while declared query methods receive no transaction configuration automatically. The readOnly flag is propagated as a JDBC hint and may enable provider optimizations; it is not a routing switch and is not a guarantee that a manipulating query will be rejected.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
Declare transaction boundaries for each unit of work and select the appropriate transaction manager when more than one is present. A read transaction on the primary manager still uses the primary database; it does not move that repository to the replica.
Understand replica staleness before exposing the endpoint
The tutorial demonstrates that, after employees are added through the primary repository, the read repository can still return the older set. That is an illustration of asynchronous replication, not a measured lag value or a universal waiting period. No lag measurement or built-in wait mechanism is established by the tutorial.
- Use the primary repository for read-after-write screens, confirmation responses, and workflows that require the just-committed value.
- Use the read repository for dashboards, searches and other requests where slightly old data is acceptable.
- If your business rule requires monotonic or read-your-writes behavior, implement an explicit consistency strategy rather than assuming the replica has caught up.
Failure modes and checks
Both repository types resolve to the same database
Check that the read scan references readEntityManagerFactory, that the read factory uses spring.datasource.readUrl, and that each transaction annotation selects the intended transaction manager.
A read repository is missing or duplicated
Inspect package boundaries and filters. The primary scan must exclude ReadOnlyRepository; the read scan must include it. Avoid registering a third scan that sees the same interface without a deliberate reason.
Writes appear possible through the read path
Confirm that the read interface does not extend CrudRepository or expose mutation methods. Also verify database credentials and grants: an interface-level omission is an API design choice, not proof of write denial.
Startup fails with an ambiguous bean
Use distinct bean names and references for both factories and transaction managers, mark only the intended primary beans with @Primary, and qualify injections where Spring cannot infer the correct persistence unit.
Reads show old data
Assume replication lag first. Compare the request’s consistency requirement with the repository it calls; route consistency-critical reads to the primary rather than adding an unsupported fixed sleep.
Deployment checklist
- Define the read-only repository interface without mutation methods.
- Create and runtime-retain
@ReadOnlyRepository. - Annotate only repositories safe for replica reads.
- Configure the primary scan with an exclusion filter and the primary factory references.
- Configure the read scan with an inclusion filter and the read factory references.
- Create separate data sources, EntityManagers and transaction managers; mark the primary set appropriately.
- Set and secure the read URL, credentials and database permissions.
- Test repository selection, startup wiring, failover behavior and read-after-write expectations on the exact framework versions you deploy.
What this pattern does—and does not do
It gives you explicit, reviewable routing: ordinary repositories remain on the primary EntityManager, while marked repositories use a secondary EntityManager backed by the read URL. It does not provide automatic query classification, a replica-health check, a quantified lag guarantee, or database-enforced immutability. Those concerns require separate transaction design, operational monitoring and database security.
Recommended Free Tools
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

