It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I did start learn tool kit spring jdbc. Read some documentation about transactions
in spring end their templates. Nevertheless some common things not clear to me.
1) If we have Spring Data why always heard only about Spring JDBC
Spring framework have some project like Spring MVC, Spring Security and etc. First i try to find Spring JDBC on home site of Spring, but do not found it. Instead of i found Spring Data project. After some research i found what Spring Data used Spring JDBC in JDBC Extensions sub-project and last have some oracle specific operation what interesting to me. And i realize what did not see or hear any use or see references in tutorials to Spring Data. It really something bad?
2) Should I create new instance of JdbcTemplate every time
Next was JdbcTemplate, useful template method. All docs replete with examples of code like
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
And they also write in docs
Instances of the JdbcTemplate class are threadsafe once configured
This is misleading. Why in setDataSource method they create new instance if they can put dataSource in already created one or i misunderstood it?
3) How can we use TransactionTemplate for writing sophisticated client logic?
TransactionTemplate another one template what works with TransactionStatus. As I understand it can help me manage my transaction but how much help?
At the start of execute method of TransactionTemplate we have transactionManager.getTransaction(this). At the end of execute method we have line this.transactionManager.commit(status). Therefore, how i understand it, all what i place in doInTransaction method will execute in single transaction. But how about execute other DAOs with same transaction in another methods? It constrains to be writing client with sophisticated logic. I mean all logic must be in one method? I thought it can not be true.
What i mean when say sophisticated logic. For example i have my own template method.
/*abstract class definition*/
public final void execute(){
onPreExec();
exec();
onPostExec();
}
abstract void exec(); //client execute few DAOs methods
public void onPreExec(){}
public void onPostExec(){} //commit or rollback transaction in another method
/*other class members*/
4) Is thread-safe to use "PTM", "TD", "TS"?
Further i begin investigate what stand behind this.transactionManager.commit(status). This represent to me PlatformTransactionManager and TransactionDefinition. How i understand, at the moment when i start write this line of text, this classes can help me achieve my goal in question #3. For example i can do like this:
/*abstract class definition*/
protected PlatformTransactionManager ptm;
protected TransactionDefinition td;
protected TransactionStatus ts;//TS with PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED
public final void execute(){
onPreExec();
exec();
onPostExec();
}
abstract void exec(); //client execute few DAOs methods
public void onPreExec(){//start transaction
ts=ptm.getTransaction(td);
}
public void onPostExec(){//end transaction
if (exec.wasCompletedSuccessfully()){
dao.markJobCompleted(); //do some for fix execution completeness
ptm.commit(ts);
} else {ptm.rollback(ts);}
}
/*other class members*/
At least this looks more convenient than transactionTemplate.execute() method for some cases. Although merely divided into several parts transactionTemplate.execute() method.
But still not clear it is thread-safe? i.e. can i use it and be sure that all inner call of JDBCs callableStatment.execute() methods from jdbcTemplate will refers to this and only to this transaction. And not see another transaction in other threads.
Thanks for reading.
Regarding JdbcTemplate:
jdbc template is provided by spring to interact with database. you can use simple JDBC code to connect database and perform operations but in this case you have to handle issues related connection closing etc. Spring jdbc template handles all these issues and the end user only need to use these api and execute operations.
regarding new JDBCTemplate(), i think this is an example only i.e. you need not to create jdbc template object in each class. you can create bean of it like data source or create BaseDAO class for this.
just one more thing, please go through Spring Data Support videos. these are very good videos to learn basic of JDBC template.
You need to realize that Spring has been around for 11 years now. It's evolved. There have been lots of projects that started as ancillary to Spring that have been folded into it. Spring JDBC has been around since Rod Johnson first wrote it. Spring Data is a recent development.
Related
I'd like to learn if there are some rules / conditions that a Spring component is wrapped (proxied) by CGLIB. For example, take this case:
#Component
public class TestComponent {
}
#Service
//#Transactional(rollbackFor = Throwable.class)
public class ProcessComponent {
#Autowired
private TestComponent testComponent;
public void doSomething(int key) {
// try to debug "testComponent" instance here ...
}
}
If we let it like this and debug the testComponent field inside the method, then we'll see that it's not wrapped by CGLIB.
Now if we uncomment the #Transactional annotation and debug, we'll find that the instance is wrapped: it's of type ProcessComponent$$EnhancerByCGLIB$$14456 or something like that. It's clearly because Spring needs to create a proxy class to handle the transaction support.
But I'm wondering, is there any way that we can detect how and when does this wrapping happen ? For example, some specific locations in Spring's source code to debug into to find more information; or some documentations on the rules of how they decide to create a proxy.
For your information, I need to know about this because I'm facing a situation where some component (not #Transactional, above example is just for demonstrating purpose) in my application suddenly becomes proxied (I found a revision a bit in the past where it is not). The most important issue is that this'll affect such components that also contain public final methods and another issue (also of importance) is that there must have been some unexpected changes in the design / structure of classes. For these kind of issues, of course we must try to find out what happened / who did the change that led to this etc...
One note is that we have just upgraded our application from Spring Boot 2.1.0RELEASE to 2.1.10RELEASE. And checking the code revision by revision up till now is not feasible, because there have been quite a lot of commits.
Any kind of help would be appreciated, thanks in advance.
You could debug into org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(Class, String, TargetSource).
If any advisor is found, the bean will be proxied.
If you use a #Lookup method injection it will also proxy the component class.
I'd like to ask whether it is alright to use apps repositories(Spring Data based) to fill in testing data. I know I can use sql file with data, but sometimes I need something more dynamical. I find writing sql or datasets definitions cumbersome(and hard to maintain in case of schema change). Is there anything wrong with using app repositories? There are all basic CRUD operations already there. Note we are talking especially about integration testing.
I feel it is kind of weird to use part of app to test itself. Maybe I can create another set of repositories to be used in test contexts.
No, there is absolutely nothing wrong with using Spring Data repositories to create test data.
I even prefer that since it often allows for simpler refactoring.
As with any use of JPA in tests you need to keep in mind that JPA implementations are a write-behind cache. You probably want to flush and clear the EntityManager after setting up the test data, so that you don't get anything from the 1st level cache that really should come from the database. Also, this ensures data is actually written to the database and problems with that will surface.
You might be interested in a couple of articles about testing with Hibernate. They don't use Spring Data, but it would work with Spring Data JPA just the same.
I would recommand to use Flyway to setup your databases and use Flyway test extension for integration testing.
So that you can do something like that:
#ContextConfiguration(locations = {"/context/simple_applicationContext.xml"})
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
FlywayTestExecutionListener.class})
#Test
#FlywayTest(locationsForMigrate = {"loadmsql"}) // execution once per class
public class MethodTest extends AbstractTestNGSpringContextTests {
#BeforeClass
#FlywayTest(locationsForMigrate = {"loadmsql"}) // execution once per class
public static void beforeClass() {
// maybe some additional things
}
#BeforeMethod
#FlywayTest(locationsForMigrate = {"loadmsql"}) // execution before each test method
public void beforeMethod() {
// maybe before every test method
}
#Test
#FlywayTest(locationsForMigrate = {"loadmsql"}) // as method annotation
public void simpleCountWithoutAny() {
// or just with an annotation above the test method where you need it
}
I'm writing an application meant to manage a database using both JDBC and JPA for an exam. I would like the user to select once at the beginning the API to use so that all the application will use the selected API (whether it be JPA or JDBC).
For the moment I decided to use this approach:
I created an interface for each DAO class (e.g. interface UserDAO) with all needed method declarations.
I created two classes for each DAO distinguished by the API used (e.g UserDAOImplJDBC and UserDAOImplJPA). Both of them implement the interface (in our case, UserDAO).
I created a third class (e.g. UserDAOImpl) that extends the JDBC implementation class. In all my code I've been always using this class. When I wanted to switch to the JPA I just had to change in all DAO classes the extends ***ImplDAOJDBC to extends ***ImplDAOJPA.
Now, as I'm starting having many DAO classes it's starting being complicate to modify the code each time.
Is there a way to change all extends faster?
I was considering adding an option in the first screen (for example a radioGroup) to select JDBC or JPA. But yet I have no idea how to make it work without having to restructure all code. Any idea?
Use a factory to get the appropriate DAO, every time you need one:
public class UserDaoFactory {
public UserDao create() {
if (SomeSharedSingleton.getInstance().getPersistenceOption() == JDBC) {
return new UserDAOImplJDBC();
}
else {
return new UserDAOImplJPA();
}
}
}
That's a classic OO pattern.
That said, I hope you realize that what you're doing there should really never be done in a real application:
there's no reason to do the exact same thing in two different ways
the persistence model of JPA and JDBC is extremely different: JPA entities are managed by the JPA engine, so every change to JPA entities is transparently made persistent. That's not the case with JDBC, where the data you get from the database is detached. So the way to implement business logic is very different between JPA and JDBC: you typically never need to save any change when using JPA.
You got 1 and 2 right, but 3 completely wrong.
Instead of having Impl extending one of the other implementations, choose which implementation to initialize using a utility method, for example. That's assuming you don't use Dependency Injection framework such as Spring.
UserDAO dao = DBUtils.getUserDAO();
public class DBUtils {
public static boolean shouldUseJdbc() {
// Decide on some configuration what should you use
}
public static UserDAO getUserDAO() {
if (shouldUseJdbc()) {
return new UserDAOImplJDBC();
}
else {
return new UserDAOImplJPA();
}
}
}
This is still jus an examle, as your DAOs don't need to be instantiated each time, but actually should be singletons.
I have made simple application for study perpose and i want to write some unit/intagration tests. I read some information about that i can mock data base insted of create new db for tests. I will copy the code which a write. I hope that some one will explain me how to mock database.
public class UserServiceImpl implements UserService {
#Autowired
private UserOptionsDao uod;
#Override
public User getUser(int id) throws Exception {
if (id < 1) {
throw new InvalidParameterException();
}
return uod.getUser(id);
}
#Override
public User changeUserEmail(int id, String email) {
if (id < 1) {
throw new InvalidParameterException();
}
String[] emailParts = email.split("#");
if (emailParts[0].length() < 5) {
throw new InvalidParameterException();
} else if (!emailParts[1].equals("email.com")) {
throw new InvalidParameterException();
}
return uod.changeUserEmail(id, email);
}
This above i a part of the code that i want to test with the mock data base.
Generally you have three options:
Mock the data returned by UserOptionsDao as #Betlista suggested, thus creating a "fake" DAO object.
Use an in-memory database like HSQLDB to create a database with mock data when the test starts, or
Use something like a Docker container to spin up an instance of MySQL or the like and populate it with data, so you can restart it as necessary.
None of these solutions are perfect.
With #1, your test will skip the intermediate steps of authenticating to the database and looking for data. That leaves a part of your code untested, and as they say, "the devil is in the details." Often people run into problems when they mock DAO's like this when they try to deploy.
With #2, you connect to an actual database, but you have to make sure that either you are using the exact same type of database in your production code or something compatible. It also makes debugging a pain because you have to pause the test to see the contents of the database if something goes wrong.
With #3, you avoid all the problems with #1 and #2, but then you have to wire up all the Docker stuff. (I'm doing this right now, and I'm having problems too). The advantage, though, is that like #2 you can set up all of your test data at once, and be guaranteed that the production database you choose will be exactly the same as your unit test.
In your case, I would go with #2 since the application is for study purposes. Yes, I know this is a long-winded answer, but as you gain experience, you will probably want to know how to "scale up."
What you can do very easily is to have your implementation of UserOptionsDao in test package and set this one to UserServiceImpl. This new implementation can return fixed set of data for example...
This is a highlevel idea. You probably do not want to have many implementations (different for each test in general), so you should use some mocking framework like Mockito or EasyMock, look at the documentation for more details.
I have some hibernate code and I want my code run in 1 transaction
let me explain in code
public void changeBranch(Branch branch) throws DatabaseException {
//some code
humanDao.update(he);
superBranchUsername = branch.getFatherUsername();
int superBranchId = branchDao.getBranchIdByUserName(superBranchUsername);
BranchEntity superBranch = branchDao.load(superBranchId);
BranchEntity be = new BranchEntity();
setBranchEntity(be, he, pkId, bname, confirmed, level, studentCount, uname, superBranch);
branchDao.update(be); // update kardane jadvale Branch va Set kardane Human motenazer be on
//some code
}
Both humanDao.update(he); and branchDao.update(be); run in transaction handle by My GenericDAO that humanDao and branchDao are inherited from it.
but I want this block of code (wrote above) to also run in a transaction!! How can I get to Hibernate to do this?
DAOs should not handle transactions for exactly the reason you've discovered: they can't know when they're part of a larger transaction.
If you were using Spring declarative transactions, you'd have a service layer that would create the transaction context for both DAOs and deal with everything. I would recommend doing something like that.
UPDATE: I added a link to Spring.
Please see: Chapter 11. Transactions and Concurrency
I find how should I fix it if I new session in changeBranch(Branch branch) and pass this session as a parameter to my DAO my problem solved