i have PC A that has a running wamp server with mysql database.
and PC B that wants to connect to that database, i am using Spring jpa, JDBC, trying to obtain direct access.
what i have done so far ?
the PC A connects to the database just fine as it is local.
PC B had no permissions to connect, "access denied" exception was thrown so i did the following :
GRANT ALL PRIVILEGES ON myDB To 'root'#'myip' IDENTIFIED BY 'root';
however, second try , another exception was thrown that says, user ''#'myip' has no privileges !
anyways just to make sure, i gave and empty user all privileges on that ip.
but still exception "select command denied" is thrown ,,(pretty sure it cant see the database)
these are my database.properties :
javax.persistence.jdbc.url=jdbc:mysql://myIp:3306/myDB?useUnicode=yes&characterEncoding=UTF-8&characterSetResults=UTF-8
javax.persistence.jdbc.user=root
javax.persistence.jdbc.password=root
hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring config :
#Configuration
#EnableJpaRepositories("chechecn.elections.organizer.repository")
#EnableTransactionManagement
public class SpringConfig {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
#Bean(name = "entityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("chechecn.elections.organizer");
factory.setJpaProperties(additionalJpaProperties());
// factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
private Properties additionalJpaProperties() {
Properties properties = PropertiesReader.instance.getPropValues(PropertiesConstants.DATABASE_PROPERTIES);
return properties;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
#Bean
public ServiceConnector serviceConnector() {
return new ServiceConnector();
}
}
Are you sure that you have root access for the other machine at that address?
Related
Can someone please guide me, how I can refresh the datasource whenever the password is rotated for the database.
Basically I don't want any manual step to refresh the datasource(like calling any endpoint). Rather than I can poll a file to see if DB credentials are rotated using FileWatcher service.
I have already read few solutions over stackoverflow regarding the same ask. But I couldn't able to implement it successfully.
Since I am new to stackoverflow can't comment on others question to get solution clarified.
Below is simple class for creating the connection pool.
#Configuration
#EnableTransactionManagement
public class JpaConfig {
#Value("${db.username}")
private String username;
#Value("${db.password}")
private String password;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.example");
factory.setDataSource(dataSource());
Properties properties = new Properties();
properties.put("hibernate.format_sql", true);
properties.put("hibernate.show_sql", true);
properties.put("hibernate.hbm2ddl.auto", "none");
properties.put("hibernate.generate_statistics", false);
factory.setJpaProperties(properties);
return factory;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
private DataSource dataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("db_connection_url");
hikariConfig.setUsername(username);
hikariConfig.setPassword(password);
hikariConfig.setPoolName("test_pool");
HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
return hikariDataSource;
}
}
You can use "Spring Cloud Bus". And whenever you change the datasource password configuration, your service can listen for this event so that it can create a new bean based on the new configuration.
Please look at this document
https://spring.io/projects/spring-cloud-bus
This repo has solution for this question : https://github.com/visa2learn/spring-cloud-vault-db-cred-rotation
I find it quite useful.
Just to make solution better read about SecretLeaseContainer :
Event-based container to request secrets from Vault and renew the associated Lease. Secrets can be rotated, depending on the requested RequestedSecret.getMode()
MY STRUCTURE:
An Authentication server, using Keycloak
One Tomcat 8 Servers
An app ( called A) with common service to all other the WebApps, located on tomcat 8 server
Other webApps
MySQL server DB, with different schemas for w/r.
A readable SQL Server
All my webApps are developed in Spring Boot, with Java 8.
CASE:
In one of the specified application (called B) I call an API of A.
This API open a connection with the SQL Server, for read an entry and send to B the value of reading entry.
I test it with A and B running in my local machine, and A official and B local.
In test I don't have any problem, the API works fine.
But when I call this API from official to official, after some seconds I had some errors in log and I lost all the connection to my Databases:
Forwarding to error page from request [/mycontroller/request] due to exception
[org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#5ec9a879 has been closed already]
java.lang.IllegalStateException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#5ec9a879 has been closed already
or:
EntityManager is closed
After this error I can only restart my Tomcat Server to restore the connection with the databases.
This is my code, that called API:
#Override
public void apiCalled() {
try {
for(Entity c : entityRepository.findEntity()) {
String ftt = keycloakRestTemplate.getForEntity(URI.create(mux+"/api/apiCalled?num="+c.getNumber()), String.class).getBody();
if(ftt == null) {
continue;
}
FttDto f = new ObjectMapper().readValue(ftt, FttDto.class);
c.setNumberF(f.getNumberF());
c.setDateF(convertDate(f.getDateF()));
commessaRepository.save(c);
}
} catch (RestClientException | IOException e) {
LOG.error("Api Service Get error: {}", e.getMessage());
}
}
Code of the API:
#PersistenceContext(unitName="persistenceUnitI24")
private EntityManager emI24;
public FttDto findByNumber(String number) {
Session session = emI24.unwrap(Session.class);
FttI24 fttListI24 = (FttI24) session.createQuery("select f from FttRg r join r.idFttI24 f join r.nota n where n.nota like '%"+number+"%'")
.setCacheMode(CacheMode.IGNORE)
.uniqueResult();
if(fttListI24 == null) {
return null;
}
FttDto ftt = new FttDto();
ftt.setNumberF(fttListI24.getNumberF());
ftt.setDateF(fttListI24.getDateF());
return ftt;
}
Any ideas?
EDIT
This is my server.xml for my DBs connection:
<Resource
name="jdbc/schemaA"
auth="Container"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
type="javax.sql.DataSource"
initialSize="2"
maxActive="4"
maxIdle="2"
minIdle="1"
username="user"
password="password"
driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://sqlServer_ip/schemaA"
testOnBorrow="true"
testWhileIdle="true"
validationQuery="select 1"
validationInterval="300000"/>
<Resource
name="jdbc/schemaB"
auth="Container"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
type="javax.sql.DataSource"
initialSize="4"
maxActive="8"
maxWait="10000"
maxIdle="8"
minIdle="4"
username="userB"
password="passB"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://mysqlserver_ip/schemaB?zeroDateTimeBehavior=convertToNull"
testOnBorrow="true"
testWhileIdle="true"
validationQuery="select 1"
validationInterval="300000" />
Adding DataSource Config in spring.
on WebApp B:
#Configuration
#EnableTransactionManagement
public class DataSourceConfig {
#Bean(name = "dataSource")
#ConfigurationProperties(prefix="spring.datasource")
#Primary
public DataSource dataSource() throws NamingException {
if(Arrays.asList(environment.getActiveProfiles()).contains("dev")) {
return new BasicDataSource();
}else {
Context ctxConfig = new InitialContext();
return (DataSource) ctxConfig.lookup("java:comp/env/jdbc/schemaB");
}
}
#Bean
#Primary
public JpaTransactionManager transactionManager() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter(){
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLInnoDBDialect");
return jpaVendorAdapter;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("domain.mydomain");
entityManagerFactoryBean.setPersistenceUnitName("persistenceUnit");
return entityManagerFactoryBean;
}
}
on WebApp A:
#Configuration
public class DataSourceI24Config {
#Autowired
private Environment environment;
#Bean(name = "dataSourceI24")
#ConfigurationProperties(prefix = "spring.datasource.i24")
public DataSource dataSourceI24() throws NamingException {
Context ctxConfig = new InitialContext();
return (DataSource) ctxConfig.lookup("java:comp/env/jdbc/schemaA");
}
#Bean(name="transactionManagerI24")
public JpaTransactionManager transactionManagerI24() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryI24().getObject());
return transactionManager;
}
#Bean(name="entityManagerI24")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryI24() throws NamingException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSourceI24());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("appA.i24.domain");
entityManagerFactoryBean.setPersistenceUnitName("persistenceUnitI24");
[...]
return entityManagerFactoryBean;
}
}
I had a same problem like this with h2 database. The solution was use db in the multiple connection mode ( more then one possible connection, connection pool).
I am working on a Spring project that needs to connect to multiple databases.
The examples I have used are all connecting to one database using properties, set at the start of the application.
My current JPA configuration looks like this:
#Configuration
#EnableTransactionManagement
public class PersistenceJPAConfig{
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "com.google.persistence.model" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_jpa");
dataSource.setUsername( "user" );
dataSource.setPassword( "password" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
In this case, the datasource properties (driver, url, username, password) are already set. But is it possible to modify this current bean or create a new method that would allow me to modify those properties during runtime?
For example, while the application is running, is there a way for me to manually disconnect from the current database, modify the datasource properties, and reconnect to the new database instead?
You can't change this properties in runtime but if you need to use multiple databases you can create multiple persistence units. Here you can find example:
http://www.baeldung.com/spring-data-jpa-multiple-databases
The feature you're looking for is called multi-tenancy.
See, for example, this guide.
As of Spring ORM v1.4 org.springframework.boot.orm.jpa.EntityScan was deprecated in favor of org.springframework.boot.autoconfigure.domain.EntityScan.
I was going to remove deprecated annotation in favor of new one, but such replacement cause IllegalStateException:
Caused by: java.lang.IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.obtainDefaultPersistenceUnitInfo(DefaultPersistenceUnitManager.java:680) ~[spring-orm-4.3.5.RELEASE.jar:4.3.5.RELEASE]
With org.springframework.boot.orm.jpa.EntityScan annotation, application starts and works correctly.
Here is my config:
#Configuration
#EntityScan("com.app.domain")
#EnableJpaRepositories("com.app.persistence.jpa")
public class JpaInfrastructureConfig {
// ... config props
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(vendorAdapter);
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaProperties(new Properties() {{
put("hibernate.dialect", hibernateDialect);
put("hibernate.show_sql", hibernateShowSql);
put("hibernate.hbm2ddl.auto", hibernateHbm2ddl);
}});
return entityManagerFactory;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
// ...
}
It seams that I've missed something, haven't I?
If you take a look at this issue on Spring Boot's issue tracker, you'll find the behaviour changes with the new annotation, as now documented in the release notes.
In your example, the simplest change would be to add a line to call LocalContainerEntityManagerFactoryBean.setPackagesToScan(…), as suggested in the release notes.
I am facing some trouble in order to configuring spring batch with h2 db
My configuration looks like this
#Configuration
#EnableBatchProcessing
public class BatchConfiguration implements BatchConfigurer {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Driver.class.getName());
String h2Url = MessageFormat.format("jdbc:h2:file:{0}note;MODE=Oracle", System.getProperty("java.io.tmpdir"));
LOGGER.info("Using H2 with URL : {}", h2Url);
dataSource.setUrl(h2Url);
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
#Bean
public DefaultPersistenceUnitManager persistenceUnitManager() {
DefaultPersistenceUnitManager defaultPersistenceUnitManager = new DefaultPersistenceUnitManager();
defaultPersistenceUnitManager.setPersistenceXmlLocation("classpath*:/META-INF/persistence.xml");
defaultPersistenceUnitManager.setDefaultDataSource(dataSource());
return defaultPersistenceUnitManager;
}
#Bean
public HibernateJpaVendorAdapter jpaAdapter() {
HibernateJpaVendorAdapter jpaAdapter = new HibernateJpaVendorAdapter();
jpaAdapter.setDatabasePlatform(H2Dialect.class.getName());
jpaAdapter.setGenerateDdl(true);
jpaAdapter.setShowSql(true);
return jpaAdapter;
}
#Bean
public LocalContainerEntityManagerFactoryBean myEmf() {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setDataSource(dataSource());
localContainerEntityManagerFactoryBean.setPersistenceUnitManager(persistenceUnitManager());
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(jpaAdapter());
localContainerEntityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
return localContainerEntityManagerFactoryBean;
}
public JobRepository getJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource());
factory.setTablePrefix("BATCH_");
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return (JobRepository) factory.getObject();
}
public JobLauncher getJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
public JobExplorer getJobExplorer() throws Exception {
JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
factory.setDataSource(dataSource());
factory.setTablePrefix("BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
public PlatformTransactionManager getTransactionManager() {
return new JpaTransactionManager(myEmf().getObject());
}
}
When i start my job , it cannot connect to the db because the configuration is unable to retrieve the metadata ( while checking into the spring batch core. jar, i can find the h2 db schemas ) so i get the exception :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?]; nested exception is org.h2.jdbc.JdbcSQLException: Table "BATCH_JOB_INSTANCE" not found;
Any help would be appreciated
Thank you very much
A couple things:
That Exception isn't from not being able to connect to the database, but because the tables haven't been created (that Exception indicates that you can connect to the database). I don't see you running the initialization scripts.
You're overdoing all the wiring. Based on what you're doing, you shouldn't need to implement BatchConfigurer. All you need to provide is the DataSource bean. The rest should be provided for you...