I am trying to create a MyBatis custom FILE type handler for the BLOB of Postgres.
Here is the method I need to implement to fulfill the interface:
#Override
public File getNullableResult(ResultSet rs, String columnName) throws SQLException {
1.get current connection
2.get postgreSQL LargeObjectManager from current connection
3.get oid from ResultSet, so the Larget Object can be found
4.read the large object and rewrite it into a file
5.return the file
}
However I do not know how to get the current connection in this situation. Is there a way to get connection from ResultSet?
Thanks in advance,
UPDATE:
PostgreSQL implements blob (large object, not bytea) in a special (nonstandard maybe) way. It saves all blob in pg_largeobject table, and use oid as a "pointer" so you can reference the blob from your real table.
Postgres JDBC driver has separated API to handle blob. More details in the following link:
http://jdbc.postgresql.org/documentation/91/binary-data.html
You can use:
Connection connection = rs.getStatement().getConnection();
But check this method for get BLOB data directly from rs:
rs.getBinaryStream("myBlobColumn");
Related
BACKGROUND
I am new to developing API in spring boot. I have this project wherein it is connected to an Oracle DB and PostgreSQL. The Oracle DB already have an existing tables and I need to fetch some data from multiple tables and send it back as a response. The Postgres DB is where I store the users data and other some data that doesn't need to be stored in the Oracle DB. I am currently using native queries.
The Account is an entity wherein I just marked one of the columns as the #Id (It is actually not an Id but it is unique for all accounts):
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Account {
#Id
private String sampleProperty1;
private String sampleProperty2;
private String sampleProperty3;
private String sampleProperty4;
private String sampleProperty5;
}
Now I have a repository interface:
public interface IAccountRepository extends JpaRepository<Account, String> {
#Query(value = "SELECT * FROM TABLE(SAMPLE_PACKAGE.SAMPLE_FUNC_GETACCOUNTS(?1))", nativeQuery = true)
List<Account> getAllAccountsByClientNumber(String clientNumber);
}
I was able to fetch the data and JPA mapped the columns automatically to my entity. Basically I am creating an Entity (Spring boot) for the data in my Oracle DB where the only purpose of it is to map the data and send it back to the user.
QUESTIONS
Will this approach create a table in my Oracle DB? I checked the Oracle DB and there is no table. But I'm worried it might somehow create a table of ACCOUNT in the oracle DB when it is on production. If this might happen, how can I prevent it?
This scenario also applies to other functionality like fetching transaction history, creating transaction, updating the Account data that are all in the Oracle DB. Am I doing it just right or there is a better option?
Is creating an Entity without a corresponding table have a drawback in Spring boot?
Note
I know you might say that I should just use the Oracle DB and create entities based on the existing tables. But in the future of the API, it will not have a connection with the Oracle DB. I already tried using projections it was also good, but I still needed to create a Response model and mapped it then send it back to user and creating a unit tests using the projection is pretty long and it sucks haha
You can set the following property:
spring.jpa.hibernate.ddl-auto=update
update will update your database if database tables are already created and will create if database tables are not created.
I want to get the schema name from my DataSource or Connection object so that it can be used in my SQL queries dynamically. I'm using DB2 and there is no implementation of connection.getSchema() in DB2 driver.
I'm using DataSource to get connection. Since connection.getSchema() is not working, I tried another approach as given below
connection.getMetaData().getURL()
But this is returning connection URL without schema information like below:
jdbc:db2://servername:1446/DBName
But i have given schema information in the URL while creating the datasource in embeddable Container.
jdbc:db2://servername:1446/DBName:currentSchema=mySchema
I need to get schema name to use it in query. Somebody knows how to get schema name.
Try the SQL statement
values current schema
The Db2BaseDataSource has a property currentSchema, along with a getter and a setter.
There's also a property called user .
setter:
db2ds.setCurrentSchema("fred");
getter:
String x = db2ds.getCurrentSchema() ;
I am trying to save my form data into database table drivers. And using springboot with spring Data JPA . By using .save() method, database is inserting as null values. But not showing any error. I am adding my controller fie below,
DriverRepository driverRepo;
#RequestMapping(value="/driverSubmit", method=RequestMethod.POST)
public ModelAndView driverSubmit(#ModelAttribute Driver driver, Model model)
{
model.addAttribute("driver", driver);
driverRepo.save(driver);
return new ModelAndView("redirect:/dHome"); //to home page after insertoin
}
Try to test your api from swagger or postman first, and debug the code first whether you are getting values in your driver object or not. If you are getting the data in driver properly then it must be some error coming out of your form request from UI. I guess an entry of driver object is getting created in db but all the values are getting saved according to their default initial values.
Currently we are writing a page in mvc5, with an oracle sql database connected with entitiy framework 6.
We currently have two schemas in the oracle database, one for testing and the other for development. The model in entitiy framework is generated from the development database, and works perfectly with it.
The problem comes, when changing the connection string to the testing schema. When the connection string is changed the application is unable to locate the tables (as they still reference the development schemes).
Currently I can fix this, by deleting all the tables from the model, and recreating the model from the correct schema, or manually editing every file referencing the schema. Both solutions are kinda tiresome and error prone.
How is this scenario usually dealt with?
EDIT
It seems that changing the database and retaining the schema, does not produce any error. So this is only schema related.
I guess this is a perfect use case for using entity framework command interceptors. I just tried and it works perfectly, even for Entity Framework DB-First approach.
You can register a custom command interceptor like this:
DbInterception.Add(new ReplaceSchemaInterceptor(newSchema: "[my]"));
This line will replace [dbo] schema name with the [my] schema name, before the query reaches the database. Luckily, schema name is enclosed with square brackets when Entity Framework generates the command text, so it's easy to match and replace. BTW, I'm not an Oracle expert, so I'm assuming that Oracle queries also include schemas in the same format. If not, then maybe you will have to tweak the implementation a bit (to replace the schema from whatever format it is generated by EF).
ReplaceSchemaInterceptor is a class that implements IDbCommandInterceptor interface. Inside this class, you need to replace the schema with your own schema. Below is the implementation of this class:
class ReplaceSchemaInterceptor : IDbCommandInterceptor
{
private readonly string _newSchema;
public ReplaceSchemaInterceptor(string newSchema)
{
_newSchema = newSchema;
}
public void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
}
public void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
}
public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
}
public void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
}
public void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
}
public void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
command.CommandText = command.CommandText.Replace("[dbo]", _newSchema);
}
}
And lastly, the code is not perfect. You need to add some null checks for the constructor parameters, and maybe get rid of the code duplication inside implementation methods when replacing command text (extract into reusable method?). Right now it just does what you had asked for.
With fluent mappings in Entity Framework code-first you can indicate the default schema at runtime. This is one statement in OnModelCreating in your DbContext subclass, for instance:
modelBuilder.HasDefaultSchema("dev");
You're used to regenerating the model from the database, from which I conclude that the model doesn't contain many (or any) customizations that would make model generation a painstaking operation. This also should make it relatively easy to move to code-first. So I'd recommend you do that.
In Visual Studio, you can generate a code-first model from an existing database by adding an "ADO.Net Entity Data Model" from the templates that come with Entity Framework tools for Visual Studio. (Probably pre-installed). Choose the option "Code First from database" and follow the guidelines.
If you do that, you'll find a connection string in the project containing the model. This connection string may serve as template for the connection string you will put in the config file of your executing assembly. You'll notice that it doesn't look like...
metadata=res://* ... provider=System.Data.SqlClient;provider connection string="...""
This is the connection string that belongs to a database-first edmx model. It contains a path to the metadata files that are generated as resources into the assembly. Instead, the connection string will be a simple ADO.Net connection string. With code-first, EF will generate the meta data at runtime.
If you have this, you can add an entry in your config file for the default database schema and use that to set the schema as I showed above.
It looks like something we are doing here at my workplace.
Use synonyms for your objects!
A possibility would be to create synonyms dynamically for your test tables - and remove references to schema in your files
Say the user that connects is CONNECT_USER - must be different user as the schemas you're using which are SCHEM_DEV and SCHEM_TEST.
Here is how I would do the switch (Oracle PL/SQL scripting - connected as CONNECT_USER):
begin
for x in (select * from all_tables where owner='SCHEM_DEV')
loop
--- drop synonyms on SCHEM_DEV objects
execute immediate 'drop synonym '||table_name ;
--- create synonyms on SCHEM_TEST objects
execute immediate ' create or replace synonym '||table_name||' for SCHEM_TEST.'||table_name ;
end loop;
end;
/
I am using Hazelcast as caching Solution for my application.
My application has few inserts and updates to the database and these needs to be synced to Cache also.
I want to use MapStore functionality so that when I do IMap.put(), Hazelcast takes care of persisting the Object in underlying Db and also update its cache.
In the overridden store implementation, I want to call my DAO in following way to persist the Data.
public void store(Long key, Product value)
{
log.info("Storing Data for Employee {} in Database using DataStore ", value);
Long employeeId = employeeDao.create(value);
value.setId(employeeId );
}
There are few issues listed below:-
1) In put call, I want to use "key" as the "employeeId", but this is generated only after insertion happens for this record in the Db. So how do I put into the Cache when I don't have the Id.? I want Hazelcast to use the "id" generated as part of store method call (or any other way) as the key to my Object.
Imap.put(key,new Employee("name_of_Employee","age_of_employee"))
2) The MapStore implementation's store method returns a void so I cannot return the Id generated for this Object to the Client. How can I achieve this?
I tried using MapEntryListeners on the Map but the entry added callback does not return new Object. I also added PostProcessingMapStore interface to my MapStore but could not get the new Value back to client.
Please advice
You have 2 options:
1) Generate the employeeId outside of the database. You can use the IdGenerator from Hazelcast to do this.
2) If you must let the database generate the id, then you need to put the Employee in the cache manually AFTER it has been stored in the database.