I want set two different tables.i have try this first model with corresponding service,controller and respository.Everythings is fine but when i use the same code with only changing the model,and develop a set of service,controller and respository.It cannot show what i expected.
my model:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
#Data
#AllArgsConstructor
#NoArgsConstructor
#javax.persistence.Entity
#Table(schema = "order")
public class Order {
#Id
#GeneratedValue
private int id;
private String product_name;
private int quantity;}
mycontroller:
package com.javatechie.trymysql.contoller;
import com.javatechie.trymysql.Entity.Order;
import com.javatechie.trymysql.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class OrderController {
#Autowired
private OrderService service;
#PostMapping("/add/orders")
public List<Order> addOrders(#RequestBody List<Order> orders){
return service.saveOrders(orders);
}
}
service:
package com.javatechie.trymysql.service;
import com.javatechie.trymysql.Entity.Order;
import com.javatechie.trymysql.repository.OrderRepository;
import com.javatechie.trymysql.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class OrderService {
#Autowired
private OrderRepository Repository;
public List<Order> saveOrders(List<Order> order) {
return Repository.saveAll(order);
}
}
repository:
package com.javatechie.trymysql.repository;
import com.javatechie.trymysql.Entity.Order;
import com.javatechie.trymysql.Entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface OrderRepository extends JpaRepository<Order,Integer> {
}
my ide pattern is like:
com.javatechie.trymysql
-entity
--Product
--Order
-controller
--productcontroller
--ordercontroller
-service
--productservice
--orderservice
-repository
--productrespository
--orderreposiory
-productconfig
-Trymysqlapplication
Postman request:
[{
"proudct_name":"sand",
"quantity":5
},{
"product_name":"fruit",
"quantity":2
}]
error:
{
"timestamp": "2022-10-17T13:14:03.284+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/add/orders"
}
Everytime i run the server it display the following log:
Hibernate: select product0_.id as id1_1_0_, product0_.name as name2_1_0_, product0_.price as price3_1_0_, product0_.quantity as quantity4_1_0_ from product_tbl product0_ where product0_.id=?
Hibernate: select product0_.id as id1_1_0_, product0_.name as name2_1_0_, product0_.price as price3_1_0_, product0_.quantity as quantity4_1_0_ from product_tbl product0_ where product0_.id=?
But it still works fine
later i add the second table it just show me:
Hibernate: select order0_.id as id1_0_0_, order0_.product_name as product_2_0_0_, order0_.quantity as quantity3_0_0_ from order order0_ where order0_.id=?
2022-10-17 21:21:11.916 WARN 3828 --- [nio-9191-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1064, SQLState: 42000
i dont why my log file automatically generate this sql and got the error when it is not the model "product"?
I dont know which step i have done wrong when trying using the second model(order)
Extracted details from comments.
As you have table name order which is a reserved keyword in MySQL. So you have to change the table name to another name that is not a reserved keyword. Change to orders resolves the issue.
Related
I want JPA to recognize an entity, and generate the SQL necessary to create the table. I can get it to fail in one of the following ways. Below I show the error, followed by the code for the entity. The behavior changed depending on which package was used for things like Table so I deliberately showed which one was being used below.
Error: RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.woodsman.jpatutorial.orders.repositories.OrderHeaderRepository; If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table.
OrderHeader.java:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
#Entity This should be simple, but I think there's several pack
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor This should be simple, but I think there's several pack
#EqualsAndHashCode
#Table(name = "order_header")
public class OrderHeader {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id; -->
private String customerName;
}
Error: Error creating bean with name 'orderHeaderRepository' defined in com.woodsman.jpatutorial.orders.repositories.OrderHeaderRepository defined in #EnableJdbcRepositories declared on JdbcRepositoriesRegistrar.EnableJdbcRepositoriesConfiguration: Could not create query for public abstract java.util.List org.springframework.data.jpa.repository.JpaRepository.saveAllAndFlush(java.lang.Iterable); Reason: No property 'saveAll' found for type 'OrderHeader'
OrderHeaderRepository.java:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.woodsman.jpatutorial.orders.entities.OrderHeader;
#Repository
public interface OrderHeaderRepository extends JpaRepository<OrderHeader,Long>{
}
OrderHeader.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
#Entity
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
#org.springframework.data.relational.core.mapping.Table(name = "order_header",schema = "orders")
public class OrderHeader {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
private String customerName;
}
application-h2.properties
spring.datasource.url=jdbc:h2:mem:ordersdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE
spring.datasource.username=ordersadmin
spring.datasource.password=secret
spring.jpa.database=mysql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
database, ALWAYS initialize the database
spring.sql.init.mode=ALWAYS
spring.flyway.user=ordersadmin
spring.flyway.password=secret
spring.flyway.locations=db/migration,db/specific/h2
spring.flyway.defaultSchema=orders
application.properties:
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type.descriptor.sql=trace
spring.h2.console.enabled=true
spring.jpa.show-sql=true
spring.data.jdbc.reposi -->
tories.enabled=true
Update: Switched back to Spring Boot 2.7.3 and things work. Using Spring Boot version 3.0.0+ apparently removes the EnableJpaRepositories annotation. Without that annotation, and with the 3.0.0+ Spring Boot version, Spring said the entity wasn't a managed type. Per #M.Deinum's comment, I commented out spring-boot-starter-data-jdbc and the code did run, but it wouldn't actually generate the create sql.
I'm convinced that this should work in the 3.0.0-M5 Spring Boot, albeit with somewhat substantial changes to dependencies, and perhaps new annotations being added, so I'm not considering my question answered. Also, I made the entity id type Long to be consistent with the repository.
See below spring boot code
I have used JPA repository.
Controller.
Service.
Repository
BaseController
package com.controller;
import com.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class BaseController {
#Autowired
private StudentService studentService;
#GetMapping(value = "/addStudent", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> base() {
studentService.save();
return new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
}
}
StudentService.java
package com.service;
import com.model.Student;
import com.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service("studentService")
public class StudentServiceImpl implements StudentService {
#Autowired
private StudentRepository studentRepository;
#Override
#Transactional
public Student save() {
Student student = new Student();
student.setFirstName("ABC");
student.setLastName("PQR");
studentRepository.save(student);
int i = 10 / 0; //Error code
return student;
}
}
StudentRepository
package com.repository;
import com.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository("studentRepository")
public interface StudentRepository extends CrudRepository<Student, Long> {
public List<Student> findAll();
}
Application.properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#maximum number of milliseconds that a client will wait for a connection
spring.datasource.hikari.connection-timeout = 20000
#minimum number of idle connections maintained by HikariCP in a connection pool
spring.datasource.hikari.minimum-idle= 10
#maximum pool size
spring.datasource.hikari.maximum-pool-size= 10
#maximum idle time for connection
spring.datasource.hikari.idle-timeout=10000
# maximum lifetime in milliseconds of a connection in the pool after it is closed.
spring.datasource.hikari.max-lifetime= 1000
#default auto-commit behavior.
spring.datasource.hikari.auto-commit =false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.jdbcUrl=jdbc:mysql://localhost:3306/demo?autoReconnect=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.properties..hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=update
After executing save method from StudentRepository, data get inserted
immediately into database. no rollback or any other isolation levels are
working in StudentServiceImpl.java even if Error code is there.
I have tried to set "spring.datasource.hikari.auto-commit =true" setting value true, Placed #Transaction at top of the StudentServiceImpl.java class but still it didn't worked.
You do not need to mess with any hikari settings, and certainly not with autoCommit(true) as this DISABLES transactions. Delete all these properties.
Where is the "error" in your code? Spring rolls back on unchecked exceptions being thrown (not checked ones or errors), I cannot see that in your code.
What behavior do you expect? It looks fine to me.
It's probably beacause of Open Jpa in View behaviour.
Write the following line in your properties file:
spring.jpa.open-in-view=false
take a look at this if you want to know more.
I have created the basic application using Spring boot using JPA. I have added #AutoWired annotation for RatingRepo in RatingResource, but haven't added #Component annotation to RatingRepo
package com.example.demo;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.RatingsRateService.model.Rating;
import com.example.demo.RatingsRateService.model.UserRating;
#RestController
#RequestMapping("ratingsdata")
public class RatingResource {
#Autowired
RatingRepo repo;
/*
* #RequestMapping("/{movieId}") public Rating
* getRating(#PathVariable("movieId") String movieId) { return new
* Rating(movieId,7); }
*/
#RequestMapping("users/{userid}")
public UserRating getRating(#PathVariable("userid") int userid) {
List<Rating> ratings =repo.findByUserId(userid);
/*
* List<Rating> ratings = Arrays.asList(new Rating("1",4), new Rating("2",3),
* new Rating("3",2));
*/
System.out.println(ratings);
UserRating userRating = new UserRating();
userRating.setUserRating(ratings);
return userRating;
}
}
package com.example.demo;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.example.demo.RatingsRateService.model.Rating;
//to update the data in database , created the interd=face and will implement
//class,primary key
public interface RatingRepo extends JpaRepository<Rating, Integer>{
#Query(" from Rating where userid = ?1")
List<Rating> findByUserId( int userid);
}
. Still, it is working fine. Can you someone please explain why it is so? Or it is not needed to add #Component annotation for the repo?
first of there is #Repository annotation required not #Component
and #Repository also auto configure due to below:
Probably you are using spring boot
Spring Data repositories usually extend from the Repository or CrudRepository interfaces. If you are using auto-configuration, repositories will be searched from the package containing your main configuration class (the one annotated with #EnableAutoConfiguration or #SpringBootApplication) down.
ref: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-spring-data-jpa-repositories
I have the below code.
Note that I have an interface MySuperCoolEntityRepositoryContract.
And I have a "concrete interface" MySuperCoolEntityJpaRepository that implements my above MySuperCoolEntityRepositoryContract interface and JpaRepository.
All of that works fine with #ComponentScan.
I am changing my code to "java config", aka a centralized location where I can code up my DI definitions. (Also known as CompositionRoot in some circles).
The issue is when I try to "code up" the concrete for the interface. (Skip down to later in this question.
package com.me.domain.jpaentities;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
#Entity(name = "MySuperCoolEntityTableName")
public class MySuperCoolEntity implements Serializable {
#Id
#Column(name = "CoolSurrogateKeyColumn")
private String coolSurrogateKey;
#Column(name = "CoolMagicValueColumn")
private String coolMagicValue;
public String getCoolSurrogateKey() {
return this.coolSurrogateKey;
}
public void setCoolSurrogateKey(String coolSurrogateKey) {
this.coolSurrogateKey = coolSurrogateKey;
}
public String getCoolMagicValue() {
return this.coolMagicValue;
}
public void setCoolMagicValue(String coolMagicValue) {
this.coolMagicValue = coolMagicValue;
}
}
===============
package com.me.dal.repositories.interfaces;
import com.me.domain.jpaentities.MySuperCoolEntity;
import java.util.Collection;
public interface MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
=========================
package com.me.dal.repositories;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import com.me.domain.jpaentities.MySuperCoolEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Collection;
#Repository
public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String> {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
Now this issue.
package com.me.myapplication.configuration;
import com.me.dal.repositories.MySuperCoolEntityJpaRepository;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyCompositionRoot {
#Bean
public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract()
{
return new MySuperCoolEntityJpaRepository(); /* << issue is here, this is an abstract class, aka, an interface with some methods defined */
}
}
Using the super cool JpaRepository "concrete interface" aka "really an abstract class but called an interface" aka "Interface Default Methods" ( see https://dzone.com/articles/interface-default-methods-java ) ........
The exact error is:
MySuperCoolEntityJpaRepository is abstract; cannot be instantiated
I do understand the error. MySuperCoolEntityJpaRepository is abstract. I get that.
But with this super cool "just extend JpaRepository and get all kinds of default functionality".....
How do I register a concrete JpaRepository with Spring DI (specifically with "code it up" java config ?
............
I tried making it a "class".
public class MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String>
but that wants me to define all those built in methods like "findAll",etc, etc.
Spring boot magically provides implementation for the methods defined in your interface. The #EnableJpaRepositories scans all packages below the package for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository (spring data provides default imlpementations of CRUD repository through this class).
Your interface MySuperCoolEntityJpaRepository extends the interface MySuperCoolEntityRepositoryContract , but you only extend the JpaRepository on the interface MySuperCoolEntityJpaRepository which means spring will only provide the default implementations for methods in the interface MySuperCoolEntityJpaRepository . So try it like :
public interface MySuperCoolEntityRepositoryContract extends JpaRepository<MySuperCoolEntity,String>{
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
then extend this in your repository like :
#Repository
public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
Related Post : how annotation #Repository in java spring work?
I figured out a workaround. I don't really like it, but I guess it works.
I also added MySuperCoolEntityBalServiceContract (you can get the idea from just the below), so you know why/how I need to have the getAMySuperCoolEntityRepositoryContract method in my CompositionRoot class below.
I'll leave this (not marked) as the answer in case someone else has a better way, or sees issue(s) with the below. I don't like the EntitiyManager work around, but it got things moving.
package com.me.myapplication.configuration;
import com.me.apicore.managers.MySuperCoolEntityBalService;
import com.me.apicore.managers.interfaces.MySuperCoolEntityBalServiceContract;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.inject.Inject;
import javax.persistence.EntityManager;
#Configuration
public class MyCompositionRoot {
#Inject
private EntityManager entManager; /* part of the work around trick */
#Bean
public MySuperCoolEntityBalServiceContract getAMySuperCoolEntityBalServiceContract() {
return new MySuperCoolEntityBalService(this.getAMySuperCoolEntityRepositoryContract());
}
#Bean
public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract() {
//return new MySuperCoolEntityJpaRepository(); /* does not work. :( */
RepositoryFactorySupport factory = new JpaRepositoryFactory(entManager);
MySuperCoolEntityRepositoryContract repository = factory.getRepository(MySuperCoolEntityRepositoryContract.class);
return repository;
}
}
And I tweaked this (note the addition of the RepositoryDefinition annotation)
package com.me.dal.repositories.interfaces;
import com.me.domain.jpaentities.MySuperCoolEntity;
import org.springframework.data.repository.RepositoryDefinition;
import java.util.Collection;
#RepositoryDefinition(domainClass = MySuperCoolEntity.class, idClass = String.class)
public interface MySuperCoolEntityRepositoryContract {
Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
}
Im trying to do a query in Spring boot to database (http://localhost:8180/products/2) and the server responds with:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Oct 26 01:29:12 COT 2017 There was an unexpected error
(type=Internal Server Error, status=500). Missing URI template
variable 'productoId' for method parameter of type Long
This the interface
package com.beitech.orders.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.beitech.orders.model.Product;
public interface ProductJpaRepository extends JpaRepository<Product, Long> {
Product findByProductoId(Long productoId);
#Query(value = "SELECT * FROM PRODUCT WHERE PRODUCTO_ID = ?1", nativeQuery = true)
Product findByproductoId3(Long productoId);
}
This is the controller:
package com.beitech.orders.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.beitech.orders.model.Product;
import com.beitech.orders.repository.ProductJpaRepository;
#RestController
#RequestMapping("/products")
public class ProductController {
#Autowired
private ProductJpaRepository productJpaRepository;
#GetMapping(value = "/allProducts")
public List<Product> findAll(){
return productJpaRepository.findAll();
}
#GetMapping(value = "/{productId}")
public Product findByProductoId(#PathVariable final Long productoId){
return productJpaRepository.findByProductoId(productoId);
}
}
You defined
#GetMapping(value = "/{productId}")
#PathVariable final Long productoId){
There is a mismatch there between productId and productoId. If you want productId to be bound to Long productoId then you would have to declare #PathVariable(name="productId") or alternatively just rename productoId to productId or vice versa.