I dont know how to explain my problem bcause i'm dont know speak english but i'm going to try..Sorry in advance for all fault
I build a website of a game server with Spring/Hibnate & JPA..
All is good, but i dont know how to load element in other database...
Look :
I have a 3 tables -> Accounts/Players/Servers
Servers has 3 columns : id/key/database
Database represent the database where is stocked all data of this servers
I would like to connect to this database to load some elements
Configuration class :
#Configuration
#EnableTransactionManagement
#EnableCaching
public class DatabaseConfiguration {
#Autowired
private DataSource dataSource;
#Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
entityManagerFactory.setPackagesToScan("org.graviton.model");
entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactory.setJpaProperties(new Properties() {{
put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
put("hibernate.show_sql", true);
put("hibernate.hbm2ddl.auto", true);
}});
return entityManagerFactory;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
My Server class
#Data
#Entity
#Table(name = "servers")
public class Server {
#Id
#Column(name = "id")
private byte id;
#Column(name = "key")
private String key;
#Column(name = "database")
private String database;
}
You see i have a var "database" and i want to, with a service, connect to this database
#Service("serverService")
public class ServerServiceImpl implements ServerService {
#Autowired
private ServerRepository serverRepository;
#Override
#Cacheable("server")
public List<Server> findAll() {
return serverRepository.findAll().stream().sorted(Comparator.comparingInt(Server::getId)).collect(Collectors.toList());
}
}
Thank you very mouch
You need entity manager to retrieve or load data into the database.
You have already created entity manager factory. Now from this factory you will get entity manager.
use this entity manager to perform operations on the DB.
Check out this tutorial it may help you:
https://schuchert.wikispaces.com/JPA+Tutorial+1+-+Getting+Started?responseToken=abcc8885c19b3894f5318e82b29345f8
Related
First time I encounter this problem. The situation is:
I have more than 100 SQL databases, each one correspond to a different company and each one have the same three tables (same table names, same column names, same column data type).
Is there some way to map all these databases dynamically?
With dynamically I mean to have one class to which I can refer and make any CRUD operation.
After some research I could see what I wanted to do:
Basically I needed to change my data source in run time, for that I used a spring framework interface called AbstracRoutingDataSource.
Example:
Implementing AbstractRoutingDataSource:
public class MultiRoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.getCurrentDb();
}
}
DatabaseContextHolder:
public class DBContextHolder {
private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
public static void setCurrentDb(DBTypeEnum dbType) {
contextHolder.set(dbType);
}
public static DBTypeEnum getCurrentDb() {
return contextHolder.get();
}
public static void clear() {
contextHolder.remove();
}
}
Database type enum:
public enum DBTypeEnum{
DATASOURCE1("DATASOURCE1"),
DATASOURCE2("DATASOURCE2");
DBTypeEnum(final String dbTypeEnum){
this.dbTypeEnum = dbTypeEnum;
}
private String dbTypeEnum;
public String dbTypeEnum(){
return dbTypeEnum;
}
}
Persistence configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "base.packages.path",
entityManagerFactoryRef = "multiEntityManager",
transactionManagerRef = "multiTransactionManager"
)
public class PersistenceConfiguration {
private final String PACKAGE_SCAN = "base.package.path";
#Bean(name = "dataSource1")
#ConfigurationProperties("spring.datasource1")
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "dataSource2")
#ConfigurationProperties("spring.datasource2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
#Bean(name = "multiRoutingDataSource")
public DataSource multiRoutingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.DATASOURCE1, dataSource1());
targetDataSources.put(DBTypeEnum.DATASOURCE2, dataSource2());
MultiRoutingDataSource multiRoutingDataSource = new MultiRoutingDataSource();
multiRoutingDataSource.setDefaultTargetDataSource(dataSource1());
multiRoutingDataSource.setTargetDataSources(targetDataSources);
return multiRoutingDataSource;
}
#Bean(name = "multiEntityManager")
public LocalContainerEntityManagerFactoryBean multiEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(multiRoutingDataSource());
em.setPackagesToScan(PACKAGE_SCAN);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean(name = "multiTransactionManager")
public PlatformTransactionManager multiTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
multiEntityManager().getObject());
return transactionManager;
}
#Bean(name = "dbSessionFactory")
public LocalSessionFactoryBean dbSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(multiRoutingDataSource());
sessionFactoryBean.setPackagesToScan(PACKAGE_SCAN);
sessionFactoryBean.setHibernateProperties(hibernateProperties());
return sessionFactoryBean;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", true);
properties.put("hibernate.format_sql", true);
return properties;
}
}
Then you need to have all of your database information in a .properties file:
spring.datasource1.jdbcUrl=jdbc:sql:sql-url:3306/datasource1
spring.datasource1.username=username
spring.datasource1.password=password
spring.datasource1.driver-class-name= Driver
spring.datasource2.jdbcUrl=jdbc:sql:sql-url:3306/datasource2
spring.datasource2.username=username
spring.datasource2.password=password
spring.datasource2.driver-class-name= Driver
Then you need to map your entity:
#Entity
#Table(name = "table_name")
#Getter
#Setter
public class MyEntity implements Serializable {
#Id
#Column(name = "ID", columnDefinition = "varchar(17)")
private String id;
//more fields...
}
I used spring CrudRepositories interface for this entity
public interface IMyEntityRepository extends CrudRepository<MyEntity, String> {
}
Finally my controller is prepared to change datasource depending on a JSON field in my request.
JSON:
{
"dataSource":"DATASOURCE1"
//more fields ...
}
RESTController:
#PutMapping("/url/{id}")
public ResponseEntity<?> editMyEntity(#RequestBody RequestObject request #PathVariable String id){
DBContextHolder.setCurrentDb(DBTypeEnum.valueOf(request.getDataSource);
iMyEntitiRepository.getMyEntity(id);
//...
}
During a Unit test i'm trying to delete an entry from my database via Spring's CrudRepository, but it seems like nothing is happening.
The entity:
#Entity #Table(name = "FACTION")
public class Faction implements Serializable
{
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", columnDefinition = "int", nullable = false, unique = true)
private Integer id;
public Integer getId()
{
return this.id;
}
}
The repository:
public interface FactionDao extends CrudRepository<Faction, Integer>
{
}
My test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Config.class)
#Sql({ "/delete-testData.sql", "/insert-testData.sql" })
public class TestFactionDao
{
#Autowired
private FactionDao dao;
#Test
public void testDelete()
{
System.out.println(this.dao.findOne(1));
this.dao.delete(1);
System.out.println(this.dao.findOne(1));
}
}
Spring configuration:
#Configuration
#EnableJpaRepositories(basePackageClasses = Config.class)
#EnableTransactionManagement
public class Config
{
#Bean
public DataSource dataSource()
{
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
#Bean
public PlatformTransactionManager transactionManager(DataSource pDataSource)
{
return new DataSourceTransactionManager(pDataSource);
}
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource pDataSource)
{
HibernateJpaVendorAdapter tJpaVendorAdapter = new HibernateJpaVendorAdapter();
tJpaVendorAdapter.setDatabase(Database.H2);
tJpaVendorAdapter.setGenerateDdl(true);
tJpaVendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean tEntityManagerFactory = new LocalContainerEntityManagerFactoryBean();
tEntityManagerFactory.setJpaVendorAdapter(tJpaVendorAdapter);
tEntityManagerFactory.setDataSource(pDataSource);
tEntityManagerFactory.setPackagesToScan(Config.class.getPackage().getName());
return tEntityManagerFactory;
}
}
The sql scripts:
-- delete-testData.sql
delete from FACTION;
-- insert-testData.sql
insert into FACTION (ID) values
(1);
Below is the console output during the test case. As you can see, no delete operation is executed and i can still read the entity i just deleted:
Hibernate: create table FACTION (ID int generated by default as identity, primary key (ID))
Hibernate: select faction0_.ID as ID1_3_0_ from FACTION faction0_ where faction0_.ID=?
de.iavra.data.Faction#1b97f47
Hibernate: select faction0_.ID as ID1_3_0_ from FACTION faction0_ where faction0_.ID=?
Hibernate: select faction0_.ID as ID1_3_0_ from FACTION faction0_ where faction0_.ID=?
de.iavra.data.Faction#17b8fa4
I tried annoting my test method with #Rollback(false), but it doesn't seem to make any difference. Calling flush() on the dao throws an exception saying there are no pending updates.
I test your code, and the solution is to change transactionManager type from PlatformTransactionManager to JpaTransactionManager. (I think maybe PlatformTransactionManager only commit the delete when the function ends.)
So the code is:
Config.java
#Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource pDataSource) {
HibernateJpaVendorAdapter tJpaVendorAdapter = new HibernateJpaVendorAdapter();
...
You must add transaction for update and delete operations.
public class FactionService {
#Autowired
private FactionDao dao;
#Transactional
public void delete(int id){
dao.delete(id);
}
}
I have just started working in java spring framework. Am just trying to populate a simple table with columns id and a name. But am getting :
Unknown entity: org.hibernate.MappingException
I get that it is commonly encountered exception. But I couldn't fix this. You can find the The entity, dao and hibernate config am using below.
HibernateConfig.java
#Getter #Setter
#Configuration#ConfigurationProperties(prefix = "databaseConfiguration")
public class HibernateConfig {
#Value("${driverClass}")
private String driverClass;
#Value("${url}")
private String url;
#Value("username")
private String username;
#Value("password")
private String password;
#Value("${hibernateDialect}")
private String hibernateDialect;
#Value("${hbm2ddlAuto}")
private String hbm2ddlAuto;
private Integer minSize;
private Integer maxSize;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", hbm2ddlAuto);
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.c3p0.min_size", minSize);
properties.put("hibernate.c3p0.max_size", maxSize);
return properties;
}
#Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public ITestDao testDao() {
ITestDao testDao = new TestDao();
return testDao;
}
}
All the properties are being taken from the .yml file. ITestDao is the interface with abstract add() method in it.
Entity class
#Getter
#Setter
#Entity
#Table(name = "test")
public class Test {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, unique = true)
private Long id;
#Column(name = "dump", nullable = false)
private String dump;
}
Dao class
#Repository
#Transactional
#Getter
#Setter
public class TestDao implements ITestDao {
#Autowired
private LocalSessionFactoryBean sessionFactoryBean;
public Test add(Test test) {
try {
sessionFactoryBean.getObject().getCurrentSession().getTransaction().begin();
sessionFactoryBean.getObject().getCurrentSession().persist(test);
} finally {
sessionFactoryBean.getObject().getCurrentSession().getTransaction().commit();
}
return test;
}
}
A service method will call this dao with #Transactional annotated above it. But while calling this add() dao method am getting Unknown entity:
org.hibernate.MappingException
Try this way :
#Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan(new String[] { "my.package.model" });// You need to provide to adapt : my.package.model
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
Good luck
You might be missing below annotation.
#EntityScan("some.known.persistence")
The #EntityScan only identifies which classes should be used by a specific persistence context.
I m having null pointer exception in sessionFactory when i try to use DI in sessionFactory I have to turn spring 3 project into Spring 4 with no xml. I dont know what the problem i m facing, SessionFactory doesnot autowired at all. when i try to test case generic doa Add Method
here is my Configuration File for bean
#Configuration
#EnableTransactionManagement
#EnableWebMvc
#ComponentScan(basePackages = "io.github.bibekshakya35.ehealth")
public class EhealthCofiguration {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean(name = "dataSource")
public javax.sql.DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/ehealth");
dataSource.setUsername("test");
dataSource.setPassword("test123");
return dataSource;
}
#Autowired
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(javax.sql.DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.scanPackages("io.github.bibekshakya35.ehealth.model");
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.hbm2ddl.auto", "update");
return properties;
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(
sessionFactory);
return transactionManager;
}
}
to load this class i have created
public class EhealthWebAppIntializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(EhealthCofiguration.class);
ServletRegistration.Dynamic dispatcher =servletContext.addServlet("SpringDispatcher", new DispatcherServlet(applicationContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
this is my generic doa class where i m injecting SessionFactory when it try to access sessionFactory.getCurrentSession(); NPE is occur,
#Repository
#Transactional
public class HibernateDAO<T extends Serializable> implements IGenericDao<T> {
private Class<T> clazz;
Session session;
#Autowired
SessionFactory sessionFactory;
private static final Logger LOG = Logger.getLogger(HibernateDAO.class.getName());
#Override
public void setClazz(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
#Override
public void create(T entity) {
session = getCurrentSession();
LOG.log(Level.INFO, "inside create entity and you just bind your session to the current one{0}", session.toString());
session.saveOrUpdate(entity);
LOG.info("saved");
session.flush();
session.refresh(entity);
}
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
Here is my stack trace for NPE
Exception in thread "main" java.lang.NullPointerException
at io.github.bibekshakya35.ehealth.DAO.genericdao.HibernateDAO.getCurrentSession(HibernateDAO.java:115)
at io.github.bibekshakya35.ehealth.DAO.genericdao.HibernateDAO.create(HibernateDAO.java:85)
at io.github.bibekshakya35.ehealth.service.impl.user.main(user.java:46)
here is my user entity
#Entity
#Table(name = "users")
public class User implements Serializable, AbstractEntity {
#Id
#Column(name = "username",unique = true)
private String userName;
#NotNull(message = "password cannot be empty")
#Column(name = "users_password")
private String userPassword;
#Embedded
private UserProfile userProfile;
#Embedded
private AuditInfo auditInfo;
#Enumerated(EnumType.STRING)
private UserType userType;
#Column(name = "is_active")
private boolean active = true;
//getter n setter
}
In chat, You provided me with this code :
public static void main(String[] args) {
User user = new User();
IGenericDao<User> iGenericDao = new HibernateDAO<>();
user.setUserName("bibekshakya35");
user.setUserPassword("ros3");
user.setUserType(UserType.GUEST);
user.setActive(true);
UserProfile userProfile = new UserProfile();
userProfile.setAge(21);
userProfile.setBasicInfo("kdhsa");
userProfile.setEmailId("dsadas#gmail.com");
userProfile.setUserGender(UserGender.Male);
userProfile.setFullname("bibek shakya");
userProfile.setMobileNumber("45454545");
userProfile.setLandLineNumber("445444");
userProfile.setUserProfilePic("index.jsp");
user.setUserProfile(userProfile);
AuditInfo auditInfo = new AuditInfo();
auditInfo.setCreatedOn(new Date());
auditInfo.setModifiedOn(new Date());
auditInfo.setVerifiedOn(new Date());
user.setAuditInfo(auditInfo);
iGenericDao.create(user);
}
Cause of error:
As You are creating the new HibernateDAO instance like this IGenericDao<User> iGenericDao = new HibernateDAO<>(); This is creating the problem.
In the case where You are using annotations, creating new instance manually ,usually causes the above mentioned error.
Reason of error:
Spring can only autowire beans that it manages; if you call new to create a bean yourself, #Autowired fields don't get filled in (and methods like #PostConstruct aren't called).
Solution:
You need to add #autowired to the HibernateDAO which will instantiate it with the exact class which includes the real #Autowired SessionFactory.
Example:
Usually we do it in the class which is itself annotated with annotations like #Controller or #Service.
Like this
#Controller
#RequestMapping(value="/someURL")
public class mainClass {
#Autowired
HibernateDAO abc;
//Code (methods) to test Your CRUD Operations
}
Im trying to use Spring and JPA. I have a table in Oracle of which few of the fields are RAW(16 BYTE) type. My entity looks like following:
#Entity
#Table(name = "testTable")
public class TestTable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#Type(type = "uuid-binary")
private UUID id;
#Column(name = "TABLE_ID")
#Type(type = "uuid-binary")
private UUID tableId;
#Column(name = "STATUS")
private String status;
My repository class looks like the following:
#Repository
public interface TestRepository extends JpaRepository<TestTable, UUID> {
TestTable getTestTableByTableId(#Param("table_id") UUId table_id);
}
The column i'm trying to mark as #Param is not primary key. I have enabled JPA Repositories on configuration file with #EnableJpaRepositories as follows:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackageClasses = { TestRepository.class })
#EnableJpaAuditing
public class JpaConfig {
#Bean(name="entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.parameters", "true");
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(this.getDataSource());
entityManagerFactoryBean.setPackagesToScan("com.test.entity");
entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(this.vendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
public JpaVendorAdapter vendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabase(Database.ORACLE);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//datasource properties here
return dataSource;
}
#Bean()
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
return transactionManager;
}
when i autowire the repository in my controller and invoke the method defined in the repository, JPA creates SQL in the background and tried to bind the parameter, but it is binding an object reference instead of UUID as follows:
[EL Fine]: sql: 2016-08-10 09:17:22.306--ServerSession(1292029763)--Connection(678757862)--SELECT ID, TABLE_ID, STATUS FROM TESTTABLE WHERE (TABLE_ID= ?)
bind => [[B#2f6964a4]
My question is why is it binding it as an object? and how would I resolve it? thanks in advance.