Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Java_J2EE_Job_Interview_Companion

.pdf
Скачиваний:
20
Добавлен:
13.05.2015
Размер:
14.25 Mб
Скачать

320 Emerging Technologies/Frameworks…

Being called code:

interface CarDAO (){

public abstract List findCarsByColor(color);

}

interface CarDAOImpl extends CarDAO (){ public List findCarsByColor(color) {

//data access logic goes here

}

}

This tight coupling can be resolved by applying the factory design pattern and program to interfaces not to implementations driven development.

Simplified factory class implemented with a singleton design pattern:

class CarDAOFactory {

private static final CarDAOFactory onlyInstance = new CarDAOFactory();

private CarDAOFactory(){}//private so that cannot be instantiated from outside the class

public CarDAOFactory getInstance(){ return onlyInstance;

}

public CarDAO getDAO(){

//if the implementation changes to FastCarDAOImpl then change here only instead of 10 //different places.

return new CarDAOImpl();

}

}

Now the caller code should be changed to:

class CarBO {

public void getCars(String color) {

//if you need to use a different implementation class say FastCarDAOImpl then need to //make one change only to the factory class CarDAOFactory to return a different //implementation (i.e. FastCarDAOImpl) rather than having to change all the callers.

CarDAO dao = CarDAOFactory.getInstance().getDAO();

List listCars = dao.findCarsByColor(color);

}

}

But the factory design pattern is still an intrusive mechanism because servicing objects need to be requested explicitly. Also if you work with large software systems, as the system grows the number of factory classes can become quite large. All the factory classes are simple singleton classes that make use of static methods and field variables, and therefore cannot make use of inheritance. This results in same basic code structure repeated in all the factory classes.

Dependency Injection (aka Inversion of Control -- IoC)

CarBO

(Caller)

getCarDAO()

Inject dependency

CarDAO

 

(via constructor or setter method setCarDAO(..))

(being called)

 

Use accessor method getCarDAO() or the instance variable carDAO set via the constructor to access the CarDAO object.

Note: being called or dependent data access object CarDAO is injected into the caller business object CarBO via annotations or XML based descriptor files.

Let us look at how dependency injection comes to our rescue. It takes the approach that clients declare their dependency on servicing objects through a configuration file (like spring-config.xml) and some external piece of

Emerging Technologies/Frameworks…

321

code (e.g. Spring) assumes the responsibility of locating and instantiating these servicing components and supplying the relevant references when needed to the client code whereby acting as the factory objects. This external piece of code is often referred to as IoC (specifically known as dependency injection) container or framework.

SpringConfig.xml

<beans>

<bean id="car" class="CarBO" singleton="false" > <constructor-arg>

<ref bean="carDao" /> </constructor-arg>

</bean>

<bean id="carDao” class="CarDAOImpl" singleton="false" />

</beans>

Now your CarBO code changes to: class CarBO {

private CarDAO dao = null;

public CarBO(CarDAO dao) { this.dao = dao;

}

public void getCars(String color) {

//if you need to use a different implementation class say FastCarDAOImpl then need to //make one change only to the SpringConfig.xml file to use a different implementation //class(i.e. class=”FastCarDAOImpl”) rather than having to change all the callers.

List listCars = dao.findCarsByColor(color);

}

}

Your calling code would be (e.g. from a Web client or EJB client ):

ApplicationContext ctx = new FileSystemXmlApplicationContext("SpringConfig.xml");

//lookup “car” in your caller where “carDao” is dependency injected using the constructor. CarBO bo = (CarBO)ctx.getBean("car"); //Spring creates an instance of the CarBO object with

//an instance of CarDAO object as the constructor arg.

String color = red; bo.getCars(color)

You can use IoC containers like Spring framework to inject your business objects and DAOs into your calling classes. Dependencies can be wired by either using annotations or using XML as shown above. Tapestry 4.0 makes use of the Hivemind IoC container for injecting application state objects, pages etc.

IoC or dependency injection containers generally control creation of objects (by calling “new”) and resolve dependencies between objects it manages. Spring framework, Pico containers, Hivemind etc are IoC containers to name a few. IoC containers support eager instantiation, which is quite useful if you want self-starting services that “come up” on their own when the server starts. They also support lazy loading, which is useful when you have many services which may only be sparsely used.

Q 10: What are the different types of dependency injections? FAQ

A 10: There are three types of dependency injections.

Constructor Injection (e.g. Pico container, Spring etc): Injection is done through constructors.

Setter Injection (e.g. Spring): Injection is done through setter methods.

Interface Injection (e.g. Avalon): Injection is done through an interface.

Spring supports both constructor-based injection and setter-based injection. The above example on Q9 is based on the constructor-based injection. Here is the same example using the Spring’s setter-based injection.

SpringConfig.xml

<beans>

<bean id="car" class="CarBO" singleton="false" >

322

Emerging Technologies/Frameworks…

<property

name=”dao”>

ref bean="carDao" /> </property>

</bean>

<bean id="carDao” class="CarDAOImpl" singleton="false" /> </beans>

Now your CarBO code changes to: class CarBO {

private CarDAO dao = null;

public CarBO() {} ….

public void setDao(CarDAO carDao){ this.dao = carDao;

}

public void getCars(String color) {

//if you need to use a different implementation class say FastCarDAOImpl then need to //make one change only to the SpringConfig.xml file to use a different implementation //class(i.e. class=”FastCarDAOImpl”) rather than having to change all the callers.

List listCars = dao.findCarsByColor(color);

}

}

The above SpringConfig.xml code creates an instance of CarBO object and CarDAO object and calls the setDao(CarDAO carDao) method, passing in the reference to the CarDAO object.

Your caller code would be (e.g. from a Web client or EJB client ) same as above:

ApplicationContext ctx = new FileSystemXmlApplicationContext("SpringConfig.xml");

//lookup “car” in your caller where “carDao” is dependency injected using the setter method. CarBO bo = (CarBO)ctx.getBean("car"); //Spring creates an instance of the CarBO object with

//an instance of CarDAO object and then invokes the //setter method setDao(CarDAO carDao) on CarBO.

String color = red; bo.getCars(color)

Q. Which one to use?

The choice between constructor-based injection and setter-based injection goes back to OO programming question – Should you fill fields in a constructor or setter methods?. There is no clear cut answer for this question. It is a good practice to start with constructor-based injection since it permits immutability (i.e. if your classes are meant to be immutable) and also constructors with parameters give you a clear statement of what is required to create a valid object. If there is more than one way to create a valid object then provide multiple constructors. But if you have a lot of constructor parameters then your constructors can look messy and also if you have many string based parameters then setter-based injection will be more descriptive because each setter name will indicate what the string is supposed to do (e.g. setFirstName(…), setLastName(…) etc)

Q 11: What are the benefits of IoC (aka Dependency Injection)? FAQ

A 11:

Minimizes the amount of code in your application. With IoC containers you do not care about how services are created and how you get references to the ones you need. You can also easily add additional services by adding a new constructor or a setter method with little or no extra configuration.

Makes your application more testable by not requiring any singletons or JNDI lookup mechanisms in your unit test cases. IoC containers make unit testing and switching implementations very easy by manually allowing you to inject your own objects into the object under test.

Loose coupling is promoted with minimal effort and least intrusive mechanism. The factory design pattern is more intrusive because components or services need to be requested explicitly whereas in IoC the dependency is injected into the requesting code. Also some containers promote the design to interfaces not to implementations design concept by encouraging managed objects to implement a well-defined service interface of your own.

Emerging Technologies/Frameworks…

323

IoC containers support eager instantiation and lazy loading of services. Containers also provide support for instantiation of managed objects, cyclical dependencies, life cycle management, and dependency resolution between managed objects etc.

Q 12: What is the difference between a service locator pattern and an inversion of control pattern?

A 12:

 

Service locator

Inversion Of Control (IoC)

 

The calling class which needs the dependent classes

In IoC (aka Dependency Injection) pattern the responsibility is

 

needs to tell the service locator which classes are needed.

shifted to the IoC containers to locate and load the dependent

 

Also the calling classes have the responsibility of finding

classes based on the information provided in the descriptor files.

 

these dependent classes and invoking them. This makes

Changes can be made to the dependent classes by simply

 

the classes tightly coupled with each other.

modifying the descriptor files. This approach makes the

 

 

dependent classes loosely coupled with the calling class.

 

 

 

 

 

Difficult to unit test the classes separately due to tight

Easy to unit test the classes separately due to loose coupling.

 

coupling.

 

 

 

 

 

 

 

 

 

 

Q 13: Why dependency injection is more elegant than a JNDI lookup to decouple client and the service? A 13: Here are a few reasons why a JNDI look up is not elegant:

The client and the service being looked up must agree on a string based name, which is a contract not enforced by the compiler or any deployment-time checks. You will have to wait until runtime to discover any discrepancies in the string based name between the lookup code and the JNDI registry.

The JNDI lookup code is verbose with its own try-catch block, which is repeated across the application.

The retrieved service objects are not type checked at compile-time and could result in a casting error at runtime.

Dependency injection is more elegant because it promotes loose coupling with minimal effort and is the least intrusive mechanism. Dependency is injected into requesting piece of code by the IoC containers like Spring etc. With IoC containers you do not care about how services are created and how you get references to the ones you need. You can also easily add additional services by adding a new constructor or a setter method with little or extra configuration.

Q 14: Explain Object-to-Relational (O/R) mapping?

A 14: There are several ways to persist data and the persistence layer is one of the most important layers in any application development. O/R mapping is a technique of mapping data representation from an object model to a SQL based relational model.

O/R mapping is well suited for read Æ modify Æ write centric applications and not suited for write centric applications (i.e. batch processes with large data sets like 5000 rows or more) where data is seldom read. Although this was generally true of many earlier O/R mapping frameworks, most today (including latest Hibernate) allow for efficient ways of performing large batch style write operations. O/R mapping tools/frameworks allow you to model inheritance (Refer Q101 in Enterprise section), association and composition class relationships. O/R mapping tools work well in 80-90% of cases. Use basic database features like stored procedures, triggers etc, when O/R mapping is not appropriate. Keep in mind that no one size fits all solution. Always validate your architectural design with a vertical slice and test for performance. Some times you have to handcraft your SQL and a good O/R mapping (aka ORM) tool/framework should allow that. O/R mapping tools/frameworks allow your application to be:

Less verbose (e.g. transparent persistence , Object Oriented query language , transitive persistence etc)

More portable (i.e. vendor independence due to multi dialect support )

More maintainable (i.e. transparent persistence, inheritance mapping strategies, automatic dirty checking etc).

Takes care of much of the plumbing like connection establishment, exception handling, configuration etc. You can often leverage the framework’s strategies and capabilities to get efficiencies. Also provides support for eager fetching, lazy loading (i.e. using proxy objects), caching strategies and detached objects (no DTOs required). Hibernate is a popular O/R mapping (aka ORM) framework, which provides above mentioned benefits and features.

324

 

Emerging Technologies/Frameworks…

 

 

D a t a a c c e s s - O /R m a p p in g

 

 

P e r s is te n t O b je c ts

 

O /R m a p p in g

 

 

 

 

 

 

P e r s is te n t O b je c ts

 

t o o l

 

 

DAOinterface

e . g . H ib e r n a te

Application

BusinessDelegate

[Transactionaldemarcation]

DAOImpl

 

 

 

 

J D B C ( d ir e c t a c c e s s )

 

 

E J B C o n ta in e r

 

 

 

(Session)EJB

EJB(Entity)

 

 

 

R M I /I IO P

 

 

R e la t i o n a l D a t a b a s e ( R D B M S )

Q.Have you used any of the frameworks using paradigms like IoC, AOP, O/R mapping tool, POJO & POJI based development, component based Web frameworks etc. Where do these frameworks fit in?

Browser (Web client)

 

Web Container

 

This shaded area work at a higher

I

level of abstraction by burying the

Servlet API deep down. Very

n

useful when building large

t

applications & applications with

e

common behavior.

 

r

Component based Web

n

frameworks like

e

Tapestry, JSF etc

 

t

 

 

Request based Web

 

framework

 

Spring MVC

Where do these frameworks fit in?

Application Server

EJB Container

This shaded area can be run outside the container if remote access is not required. It can be tested outside the container by injecting business objects and DAOs into the test cases. Later on can be deployed into the container along with EJBs for remote access.

EJB

SpringIOC+ AOP

SpringIOC+ AOP

SpringHibernate support/ JDBC templatesupport etc

Hibernate

 

Business

 

DAOs

 

 

Objects

 

 

 

Database

Q. What open source frameworks do you have experience with? Hibernate, IBatis, Spring, Struts, Tapestry, log4j, Ant, Quartz (scheduler, an alternative to Timer and TimerTask) etc

Q 15: Give an overview of hibernate framework? FAQ

A 15: Hibernate is a full-featured, open source Object-to-Relational (O/R) mapping framework. Unlike EJB (EJB’s new persistence API can operate outside of an EJB container), Hibernate can work inside or outside of a J2EE container. Hibernate works with Plain Old Java Objects (POJOs), which is much like a JavaBean.

Q. How will you configure Hibernate?

The configuration files hibernate.cfg.xml (or hibernate.properties) and mapping files *.hbm.xml are used by the Configuration class to create (i.e. configure and bootstrap hibernate) the SessionFactory, which in turn creates the Session instances. Session instances are the primary interface for the persistence service.

Emerging Technologies/Frameworks…

325

hibernate.cfg.xml (alternatively can use hibernate.properties): These two files are used to configure the hibernate service (connection driver class, connection URL, connection username, connection password, dialect etc). If both files are present in the classpath then hibernate.cfg.xml file overrides the settings found in the hibernate.properties file.

Mapping files (*.hbm.xml): These files are used to map persistent objects to a relational database. It is the best practice to store each object in an individual mapping file (i.e. mapping file per class) because storing large numbers of persistent classes into one mapping file can be difficult to manage and maintain. The naming convention is to use the same name as the persistent (POJO) class name. For example Account.class will have a mapping file named Account.hbm.xml. Alternatively hibernate annotations can be used as part of your persistent class code instead of the *.hbm.xml files.

Q. What is a SessionFactory? Is it a thread-safe object?

SessionFactory is Hibernate’s concept of a single datastore and is threadsafe so that many threads can access it concurrently and request for sessions and immutable cache of compiled mappings for a single database. A SessionFactory is usually only built once at startup. SessionFactory should be wrapped in some kind of singleton so that it can be easily accessed in an application code.

SessionFactory sessionFactory = new Configuration().configure().buildSessionfactory();

Hibernate Architecture

Primary components

Layered architecture

Transaction

 

Query

 

 

Application Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Session

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SessionFactory

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Configuration

 

 

 

 

 

 

 

 

 

hibernate.cfg.xml

 

 

Mapping files

(also hibernate.properties)

 

 

 

*.hbm.xml

 

 

 

 

 

 

 

Application

Presentation layer

Detached

Transient

Business layer

Objects

Objects

DAO layer

Persistent

Persistent

 

 

 

 

Objects

Objects

Session Factory

 

Session

Transaction

 

 

 

 

JNDI

 

JDBC

 

JTA

 

 

 

Database

 

Q. What is a Session? Can you share a session object between different threads?

Session is a light weight and a non-threadsafe object (No, you cannot share it between threads) that represents a single unit-of-work with the database. Sessions are opened by a SessionFactory and then are closed when all work is complete. Session is the primary interface for the persistence service. A session obtains a database connection lazily (i.e. only when required). To avoid creating too many sessions, ThreadLocal class can be used as shown below to get the current session no matter how many times you make a call to the currentSession() method.

public class HibernateUtil {

public static final ThreadLocal local = new ThreadLocal();

public static Session currentSession() throws HibernateException { Session session = (Session) local.get();

//open a new session if this thread has no session if(session == null) {

session = sessionFactory.openSession(); local.set(session);

}

return session;

}

}

326

Emerging Technologies/Frameworks…

It is also vital that you close your session after your unit of work completes. Note: Keep your Hibernate Session API handy.

Q. Explain hibernate object states? Explain hibernate objects lifecycle?

Persistent

Detached

Transient

Persistent objects and collections are short lived single threaded objects, which store the persistent state. These objects synchronize their state with the database depending on your flush strategy (i.e. auto-flush where as soon as setXXX() method is called or an item is removed from a Set, List etc or define your own synchronization points with session.flush(), transaction.commit() calls). If you remove an item from a persistent collection like a Set, it will be removed from the database either immediately or when flush() or commit() is called depending on your flush strategy. They are Plain Old Java Objects (POJOs) and are currently associated with a session. As soon as the associated session is closed, persistent objects become detached objects and are free to use directly as data transfer objects in any application layers like business layer, presentation layer etc.

Detached objects and collections are instances of persistent objects that were associated with a session but currently not associated with a session. These objects can be freely used as Data Transfer Objects without having any impact on your database. Detached objects can be later on attached to another session by calling methods like session.update(), session.saveOrUpdate() etc. and become persistent objects.

Transient objects and collections are instances of persistent objects that were never associated with a session. These objects can be freely used as Data Transfer Objects without having any impact on your database. Transient objects become persistent objects when associated to a session by calling methods like session.save(), session.persist() etc.

Statechart diagram

new Transient

Object

Transient

Hibernate objects lifecycle

can be garbage collected when not reachable

get()

find()

load() iterate() etc

delete()

save()

persist()

merge()

refresh()

Persistent

Object

Persistent

close()

clear()

evict()

update()

saveOrUpdate()

lock()

merge()

replicate()

Detached

Object

 

Can be garbage

Detached

collected when not

reachable

 

Car car1 = new Car()

Session session = HibernateUtil.currentSession();

 

session.save(car1);

becomes persistent car1

session.flush();

 

session.evict(car1);

session.clear(); //affects all objects in the session

becomes detached

car1

Session session = HibernateUtil.currentSession(); car1 becomes persistent session.saveOrUpdate(car1);

session.flush();

session.close()

becomes detached

car1

Session session = HibernateUtil.currentSession();

becomes persistent car2

Car car2 = session.load(Car.class, carPK);

 

car2

becomes transient

session.delete(car2);

Note: The state of the transient and detached objects cannot be synchronized with the database because they are not managed by hibernate. When a session is closed the persistent objects become detached objects. The detached objects can be re-attached to another session by invoking update(), saveOrUpdate() or lock(). Detached objects can be passed all the way up to the presentation layer and later on re-attched.

Emerging Technologies/Frameworks…

327

Q. What are the benefits of detached objects?

Detached objects can be passed across layers all the way up to the presentation layer without having to use any DTOs (Data Transfer Objects). You can later on re-attach the detached objects to another session.

Session session1 = sessionFactory.openSession();

Car myCar = session1.get(Car.class, carId); //”myCar” is a persistent object at

this stage.

session1.close();

//once the session is closed “myCar” becomes a detached

object

you can now pass the “myCar” object all the way upto the presentation tier. It can be modified without any effect to your database table.

myCar.setColor(“Red”);

//no effect on the database

When you are ready to persist this change to the database, it can be reattached to another session as shown below:

Session session2

= sessionFactory.openSession();

Transaction tx =

session2.beginTransaction();

session2.update(myCar);

//detached object ”myCar” gets re-attached

tx.commit();

 

//change is synchronized with the database.

session2.close()

 

 

When long transactions are required due to user think-time, it is the best practice to break the long transaction up into two or more transactions. You can use detached objects from the first transaction to carry data all the way up to the presentation layer. These detached objects get modified outside a transaction and later on reattached to a new transaction via another session.

Q. How does Hibernate distinguish between transient (i.e. newly instantiated) and detached objects?

• Hibernate uses the “version” property, if there is one.

• If not uses the identifier value. No identifier value means a new object. This does work only for Hibernate managed surrogate keys. Does not work for natural keys and assigned (i.e. not managed by Hibernate) surrogate keys.

• Write your own strategy with Interceptor.isUnsaved().

Q. What is a Hibernate transaction object?

Transaction is a single threaded, short lived object used by the application to specify atomicity. Transaction abstracts your application code from underlying JDBC, JTA or CORBA transactions. At times a session can span several transactions. When long transactions are required due to user think-time, it is the best practice to break the long transaction up into two or more transactions. You can use detached objects from the first transaction to carry data all the way up to the presentation layer. These detached objects get modified outside a transaction and later on re-attached to a new transaction via another session.

Transaction tx = session.beginTransaction(); Employee emp = new Employee(); emp.setName(“Brian”); emp.setSalary(1000.00);

session.save(emp);

tx.commit(); //close session

Q. How do you query the database with Hibernate?

Hibernate provides a very robust querying API that supports query strings, named queries and queries built as aggregate expressions. The most flexible way is using the Hibernate Query Language syntax (HQL), which is easy to understand and is an Object Oriented extension to SQL, which supports inheritance and polymorphism.

Query query = session.createQuery(“Select car from Car as car where car.color = :color”); query.setString(“color”,”black”);

List list = query.list();

HQL

SQL

HQL uses classes and properties instead of tables and columns.

SQL uses tables and columns and is more verbose.

HQL is less verbose than SQL and supports automatic association

 

328

 

 

 

Emerging Technologies/Frameworks…

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

joining.

 

 

 

 

 

 

 

Select car.* from Car

as

car join

Part

 

 

 

 

 

 

 

 

 

 

 

part on car.part_id

=

part.id

where

 

 

 

 

 

 

 

 

 

 

 

car.color = black’

and part.cost >

 

 

 

Select car

from Car

as

car join

car.parts

as

 

 

 

part where

car.color

=

‘black’ and

part.cost

>

 

 

100”);

 

 

 

 

 

 

100”);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Type-safe queries can be handled by the object oriented query by criteria approach.

String color = “black”;

Criteria criteria = session.createCriteria(Car.class); criteria.add(Expression.eq(“color”, color)); Collection col = criteria.list();

You can also use Hibernate’s direct SQL query feature. If none of the above meets your requirements then you can get a plain JDBC connection from a Hibernate session.

Q. How does hibernate support legacy applications?

You can use user defined data types and composite primary keys to get additional flexibility to support legacy applications. It is best practice to use wrapper classes like Boolean, Integer, Long etc instead of primitive types in your persistent classes. For example If you have a legacy application, which has the value of null for a Boolean property in its legacy table, then hibernate will throw a PropertyAccessException if you use the primitive type boolean since it cannot take the null value.

Q. Explain some of the following attributes used in *.hbm.xml mapping file?

Attribute

 

Description and possible values

 

 

Example

 

cascade

 

Lets you control your graph of objects as to how

 

<hibernate-mapping>

 

 

 

automatically any associated objects gets saved,

 

<class name=”Car” table=”car”>

 

 

 

updated or deleted. It is also known as transitive

 

….

 

 

 

persistence.

 

<set name=”parts” cascade=”all” lazy=”true”>

 

 

 

none (default): no automatic action.

 

<key column=”part_id” />

 

 

 

 

<one-to-many class=”com.Part” />

 

 

 

save-update: save or update actions are automatically

 

</set>

 

 

 

 

….

 

 

 

passed to the child entities.

 

</class>

 

 

 

delete: Delete actions are automatically passed to child

 

</hibernate-mapping>

 

 

 

 

 

 

 

 

entities.

 

 

 

 

 

delete-orphan: When a child is removed from the

 

 

 

 

 

parent, then the child is automatically deleted.

 

 

 

 

 

all: save, update and delete actions are passed to child

 

 

 

 

 

entities but not delete-orphan.

 

 

 

 

 

all-delete-orphan: save, update, delete and delete-

 

 

 

 

 

orphan actions are passed to child entities.

 

 

 

 

 

There are other cascade values such as merge,

 

 

 

 

 

replicate, persist, lock etc.

 

 

 

 

 

If you have a true composition relationship, where if the

 

 

 

 

 

parent gets deleted then the children should also be

 

 

 

 

 

deleted, then you should set the cascade attribute to all-

 

 

 

 

 

delete-orphan. For example if an Order object is deleted

 

 

 

 

 

then all its LineItem objects (i.e. children) should also be

 

 

 

 

 

deleted as well.

 

 

 

 

 

 

 

 

 

 

inverse

 

This attribute is used when you use the one-to-many and

 

//one-to-many side

 

 

many-to-one bidirectional association to indicate that

 

<hibernate-mapping>

 

 

 

many-to-one side controls the association as opposed to

 

<class name=”Car” table=”car”>

 

 

 

one-to-many side.

 

….

 

 

 

If you do not have the inverse flag or if it is set to false

 

<set name=”parts” cascade=”all” inverse=”true”>

 

 

 

 

<key column=”part_id” />

 

 

 

then the one-to-many side will control the association,

 

<one-to-many class=”com.Part” />

 

 

 

which means if you have the following scenario:

 

</set>

 

 

 

 

 

 

….

 

 

 

Car car1 = new Car(“blue”);

 

 

</class>

 

 

 

 

 

Emerging Technologies/Frameworks…

329

 

 

 

 

 

 

 

 

 

 

car1.getParts().add(new Part(“Steering”));

 

 

</hibernate-mapping>

 

 

 

 

car1.getParts().add(new Part(“Brake”));

 

 

 

 

 

 

 

 

 

session.save(car1);

 

 

 

 

 

//many-to-one side

 

 

 

This will result in 3 INSERT SQL calls (1 for the parent

 

 

 

 

 

 

 

<hibernate-mapping>

 

 

 

 

Car object

and 2 times for the Part objects). Since the

 

 

<class name=”Part” table=”part”>

 

 

 

 

association is controlled by the Car object (i.e. one-to-

 

 

….

 

 

 

 

 

many side), inserting the part objects will not set the

 

 

<many-to-one name=”car” column=”car_id” / >

 

 

 

 

foreign key value (i.e. car_id) into the Part objects. There

 

 

….

 

 

 

 

 

will be two additional UPDATE SQL calls to add the Car

 

 

</class>

 

 

 

 

 

object’s foreign key value into the Part records. So this is

 

 

</hibernate-mapping>

 

 

 

 

not only inefficient but also will cause errors during

 

 

 

 

 

 

 

 

INSERT SQL calls to Part objects if every part should

 

 

 

 

 

 

 

 

have a car (i.e. foreign-key column car_id in Part is a

 

 

 

 

 

 

 

 

not-null column).

 

 

 

 

 

 

 

 

 

 

 

The solution to overcome the above issue is to set the

 

 

 

 

 

 

 

 

attribute inverse=”true” on the Car object (i.e. one-to-

 

 

 

 

 

 

 

 

many side) to indicate that the ownership of the

 

 

 

 

 

 

 

 

association should be given to the Part objects (i.e.,

 

 

 

 

 

 

 

 

many-to-one side). Since the association belongs to the

 

 

 

 

 

 

 

 

Part objects there will never be an INSERT SQL call to

 

 

 

 

 

 

 

 

the Part record with a null car_id.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

lazy

 

This property is used to determine if all the associated

 

 

 

 

 

 

 

 

graph of objects should be “eagerly” fetched or “lazily

 

 

<hibernate-mapping>

 

 

 

 

loaded

when

methods

like

session.get(…),

 

 

<class name=”Car” table=”car”>

 

 

 

 

session.load(…), session.find(…), etc are executed. The

 

 

….

 

 

 

 

 

lazy loading uses proxy objects.

 

 

 

 

<set name=”parts” cascade=”all” lazy=”true”>

 

 

 

 

lazy= true (default on hibernate 3.0 onwards) means

 

 

<key column=”part_id” />

 

 

 

 

 

 

<one-to-many class=”com.Part” />

 

 

 

 

load associated objects lazily.

 

 

 

 

</set>

 

 

 

 

 

lazy=false means load associated objects eagerly.

 

 

….

 

 

 

 

 

 

 

</class>

 

 

 

 

 

It is the best practice to set the lazy attribute to true in

 

 

</hibernate-mapping>

 

 

 

 

 

 

 

 

 

 

 

 

the mapping file and make it a conscious choice to

 

 

//session should be open to access a proxy object

 

 

 

eagerly join in your HQL or eagerly fetch in your criteria

 

 

 

 

 

query for specific use cases. For e.g.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Session session= sessionFactory.openSession();

 

 

 

 

String hqlQuery = “ FROM Car c OUTER JOIN FETCH

 

 

Car car = session.load(Car.class, 12);// id =12

 

 

 

 

 

 

c.parts WHERE c.color=?”;

 

 

Set parts = car.getParts();

 

 

 

 

If you want to access a lazily initialized collection, you

 

 

session.close();

//session is closed.

 

 

 

 

 

 

Part part1 = (Part)parts.get(0); //exception is thrown

 

 

 

 

must make sure that the session is open, otherwise an

 

 

 

//because the session is closed

 

 

 

 

exception will be thrown.

 

 

 

 

 

 

 

 

 

 

You could also optimize your lazy loading strategy by

 

 

 

 

 

 

 

 

specifying the batch-size attribute as discussed next.

 

 

 

 

 

 

batch-size

 

This is used as an optimization strategy for loading

 

 

<hibernate-mapping>

 

 

 

 

objects lazily. Hibernate can load several uninitialized

 

 

<class name=”Car” table=”car”>

 

 

 

 

proxy objects if one proxy object or collection is

 

 

….

 

 

 

 

 

accessed.

 

 

 

 

 

 

<set name=”parts” batch-size=”20”>

 

 

 

 

For example, say you have 50 Car objects loaded into a

 

 

<key column=”part_id” />

 

 

 

 

 

 

<one-to-many class=”com.Part” />

 

 

 

 

session with a session.find(….) query operation. Say

 

 

</set>

 

 

 

 

 

each car object has an association with a collection of 10

 

 

….

 

 

 

 

 

Part objects. So if you iterate through all your Car

 

 

</class>

 

 

 

 

 

objects, there will be 50 SQL

SELECT calls to the

 

 

</hibernate-mapping>

 

 

 

 

database for every invocation of car.getParts() method.

 

 

 

 

 

 

 

 

If you set your batch-size attribute to 20, then there will

 

 

 

 

 

 

 

 

be only 3 SQL SELECTs to the database. Hibernate will

 

 

 

 

 

 

 

 

load 20,20,10 collections in just 3 SELECT calls.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

unsaved-

 

unsaved-value attribute comes into play when you use

 

 

<hibernate-mapping>

 

 

value

 

the saveOrUpdate(…) method.

 

 

 

 

<class name=”Car” table=”car”>

 

 

 

 

 

 

 

 

 

 

 

<id name=”id” column=”car_id” type=”long”

 

 

 

 

null is the default value. Other values supported are

 

 

 

unsaved-value=”null”>

 

 

 

 

any, none, and id-value.

 

 

 

 

<generator class=”native” />

 

 

 

 

 

 

 

 

 

 

 

</id>

 

 

 

 

 

If the unsaved-value is set to null or not set at all (default

 

 

<set name=”parts” cascade=”all” lazy=”true”>

 

 

 

 

value is null) and if the primary-key property value is null

 

 

<key column=”part_id” />

 

 

 

 

then hibernate assumes that the object is transient and

 

 

<one-to-many class=”com.Part” />

 

 

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]