Read database object with spring boot and h2 - spring

I want to know how to read database object from h2 database into my spring controller using hibernate (or anything really, I am not married to hibernate).
I have a simple project setup using gradle.
And my application.properties is
spring.thymeleaf.cache=false
# Datasource
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:database
spring.datasource.username=something
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
# H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
# Hibernate
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
I can see that schema.sql and data.sql are being executed. And I see my table exists with data inside of it using h2 console. I have an entity object made too.
However I have no idea how I would go about reading my entity object from h2 and into my controller. Can someone point to the right resource or explain how to go about doing it?

By far the simplest approach to this is to use spring-data-jpa. To do this you need an entity (that is, a class with an #javax.persistence.Entity annotation) that will represent a row in your table.
#Entity
public class Thing {
#Id
private String id;
private String name;
}
Then you need a repository that can read and write from the DB. This is an interface that extends one of the spring repository classes, usually CrudRepository, like this:
public interface CustomerRepository extends CrudRepository<Thing, String> {
Thing findById(long id);
}
Then, autowire the repo into your controller's constructor, and you're nearly finished. The last part is calling one of the methods on the repo. You don't have to actually implement the repo, spring will do that for you. The base repo has plenty of useful default methods that you don't even have to list in your code. There are plenty of references for all of this on spring's website and I've linked you to a good tutorial for it (it has gradle examples, but you should really be using maven because it's a lot better in every possible respect).

Related

#Transient - Why data is getting saved in Database?

I have an entity variable annotated with #Transient like below. Which means it should not be stored in the Database.
#Transient
private String passwordConfirm;
But when I go to H2-Console, I can see the data is saved there.
Why so? and How can I avoid it?
You're probably using #org.springframework.data.annotation.Transient.
Change it to the right import: #javax.persistence.Transient
This will do the job.
#javax.persistence.Transient is used by the persistence provider (eg.: Hibernate). The persistence provider looks for JPA spec annotations. #org.springframework.data.annotation.Transient is not a part of the JPA spec, so, the persistence provider ignores it.
The #org.springframework.data.annotation.Transient is intended to be used when Spring Data is the actual ORM. Some examples are Spring Data Elasticsearch and Spring Data MongoDB. These Spring Data implementations use the #org.springframework.data.annotation.Transient just like Hibernate uses the #javax.persistence.Transient - not mapping the marked field into the database.

Integration test values are inserted to database

I am trying to test a JpaRepository with spring boot integration tests. I'm using the #DataJPATest annotation without the embedded db. I'm using the same MySQL db that I use for development to run integration tests.
#DataJpaTest
#AutoConfigureTestDatabase(replace = NONE)
class UserRepositoryTest {
#Autowired
UserRepository userRepository;
#Test
void findByUsername() {
User u = new User();
u.setUsername("ML");
u.setFirstname("Micheal");
u.setLastname("Lane");
u.setActive(true);
userRepository.save(u);
assertThat(userRepository.findByUsername("M21")).isNotNull();
}
}
The value I inserted in the test is inserted into the actual data base. But I thought with #DataJpaTest the transaction is rolled back at the end of the test.
By default, tests annotated with #DataJpaTest are transactional and roll back at the end of each test. They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource). The #AutoConfigureTestDatabase annotation can be used to override these settings.
So why is my data getting saved to the database? Is it because I'm not using the embedded database?
Dialect used : spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
**********************************************************8
It started to rollback once I remove findByUsername() part form the test method
User u = new User();
u.setUsername("ML");
u.setFirstname("Micheal");
u.setLastname("Lane");
u.setActive(true);
userRepository.save(u);
//assertThat(userRepository.findByUsername("M21")).isNotNull();
So I guess It doesn't work because there are 2 queries. I will have to use an already saved data for findByUsername() test
I believe it is due to the auto-wire. When you auto-wire it instantiates the interface via dependency injections. If you don't want data to be stored when running the test I suggest you look at mockito. There you can mock the repos so you can test all the methods used when storing data but never actually saves it
Can you try by using this dialect.
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
Hope this should work.

Adding new DB support in spring data

Currently spring data has multiple db support (mysql, cassandra, mongo.. very big list), however i want to add my custom repository from the scratch like adding custom db support in spring data. I don't want to extend any existing repositories, instead I want to create a parallel repository strutcutre for my custom datasource. Looking at current implementation it looks like tedious task. It would be a great if someone could help me with minimal requirement to do this.
You could create a repository annotated bean where you would inject EntityManager or the proper bean that is acting like that, depending on database type that you are using.
#Repository
public class MyCustomRepositoryImpl implements MyCustomRepository {
#Autowired
private EntityManager entityManager;
//the methods that you are going to create.
}
For more details see:
https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
Chapter: 1.3 Custom implementations for Spring Data repositories

Spring Boot: Flyway migration before mybatis initialization

In my Spring Boot app I use Flyway for DB migrations and MyBatis together. Problem is that MyBatis is initialized before Flyway, so some DB operations are called (within #PostConstruct) before DB migration.
If I take a look into FlywayAutoConfiguration there is:
#AutoConfigureAfter({DataSourceAutoConfiguration.class, ...})
public class FlywayAutoConfiguration {
...
As I understand, I need override FlywayAutoConfiguration and add:
#AutoConfigureAfter({DataSourceAutoConfiguration.class})
#AutoConfigureBefore({MybatisAutoConfiguration.class})
public class FlywayAutoConfiguration {
...
Not sure how to do that. Thanks for any help.
I would declare a #Bean definition for flyway() and then another #Bean definition for whatever data source in your possession, making sure to initialize it after the flyway bean , which you can simply do by adding #DependsOn("flyway") annotation on your data source bean declaration.
This way you make sure whatever data init tasks launched by your data source will come after flyway has done its job.

Should I annotate Spring Data Repositories with #Repository [duplicate]

I'm using Spring Data JPA repositories (like MyRepo extends JpaRepository) and it works without #Repository and without #EnableJpaRepositories annotations. Could someone explain why?
Probably you are using Spring Boot.
Spring Data repositories usually extend from the Repository or CrudRepository interfaces. If you use auto-configuration, repositories are searched from the package containing your main configuration class (the one annotated with #EnableAutoConfiguration or #SpringBootApplication) down.
Please check the Spring Boot Reference Documentation (v2.7.2) for more details.
you don't need #Repository to make use of Spring Data JPA.
The Interface extending the CrudRepository or JPARepository would work even without annotating it with #Repository.
The Core reason why you need to have this annotation in place is it makes unchecked exceptions thrown in the DAO layer eligible to be translated into Spring DataAccessException. Which in turn would be easier to work with. This is the important aspect of using #Repository
More details see this -> https://www.youtube.com/watch?v=z2re1MfWtz0&list=PLO0KWyajXMh4fGMvAw1yQ1x7mWayRcmX3&index=8&t=0s
For more information look into these class which is used to auto-configure Spring Data JPA Repositories:
JpaRepositoriesAutoConfigureRegistrar
Docs : http://www.atetric.com/atetric/javadoc/org.springframework.boot/spring-boot-autoconfigure/1.2.0.RELEASE/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigureRegistrar.html
#EnableJpaRepositories
private static class EnableJpaRepositoriesConfiguration {
}

Resources