What is the difference between checked and unchecked exceptions?
- Checked exceptions are evaluated (checked) in compile time
- Unchecked exceptions are evaluated in runtime
- Checked exceptions are all under Throwable (except Error and RuntimeException)
- Unchecked exceptions are all under Error and RuntimeException
- Use checked exceptions if it's possible to recover from the exception and continue program flow
- Unchecked exceptions are not meant to be caught (produced from unforeseen programming errors)
- Adding checked exceptions introduces boilerplate code and extra dependencies, in contrast with Spring's principle to decouple dependencies from caller code (Spring IoC/DI)
- Testing becomes more difficult
- Disrupts S.O.L.I.D principles of Spring, by introducing high coupling
- Spring isolates/abstracts DB vendor-specific exceptions (e.g. exceptions from JDBC/JPA/Hibernate implementations) and incorporates them in its own hierarchy
- Root class: DataAccessException, Main branches: NonTransientDataAccessException, RecoverableDataAccessException, TransientDataAccessException
- Examples: BadSqlGrammarException, DuplicateKeyException, EmptyResultDataAccessException, CannotGetJdbcConnectionException, QueryTimeoutException
- Access Exception Hierarchy using xxx-Template classes, e.g. JDBCTemplate
- Using Spring beans that use a JDBC driver
- SimpleDriverDataSource, DriverManagerDataSource (creates new connection per request, multi-threading ability)
- SingleConnectionDataSource (does not close connection after use, not multi-thread capable)
- Using JNDI data source bean
- JndiObjectFactoryBean
- Database external to the application
- Pooled datasources, greater performance, hot-swapping
- Using pooled datasources
- Spring does not provide by default
- Use Apache Commons DBCP, BasicDatasource
- Using embedded data source bean
- EmbeddedDatabaseBuilder
- Testing purposes
- Template design pattern defines a base class with fixed implementations regarding common functionalities (fixed part), and delegates implementation regarding specific needs (variable part) to subclasses, using callbacks
- JdbcTemplate defines connection init/close, transaction handling, clean up / releases in fixed part, and enforces implementations regarding handling result set, binding params, creating statements, in variable part.
- A callback is a function that is to be executed after another function has finished executing
- In Spring's JdbcTemplate, callbacks are used to handle a ResultSet after a query execution, and more
- Callback interfaces:
- RowCallbackHandler: handles each row of a ResultSet and can choose not to return the domain object, but to store it somewhere else
- RowMapper<T>: each row of ResultSet is mapped to domain object
- ResultSetExtractor<T>: multiple rows of ResultSet are mapped in one object
- PreparedStatementCreator: creates a prepared statement given a Connection provided by this class, providing SQL and any necessary parameters.
- Yes, using:
- execute()
- Use for DDL statements
- query()
- Provides variety for query results handling/mapping, using ResultSetExtractor, RowMapper, RowCallbackHandler
- queryForList()
- Use when we want query results for one column only (one or many rows)
- queryForObject()
- Use when we expect one row result
- queryForMap()
- Use when we expect one row result. Returns a map with [column + value]
- queryForRowSet()
- Use if column metadata are needed
- update()
- Updates, using a PreparedStatementSetter or PreparedStatementCreator
- batchUpdate()
- For every method called. query() and update() use execute() which acquires connection from connection pool. (if such one exists)
- Reason is to keep connection resource open only for as long as it's needed
- queryForObject: use when one row result is expected. Optional: call queryForObject with a callback parameter, in case of mapping result to domain object
- queryForList: use when multiple expected row results, with each containing only one column information
- queryForMap: use when single row is expected. Returns map of column names as keys and column values as values
- queryForRowSet: Returns a SqlRowSet object that contains column metadata and is iterable
- The context of execution for a group of SQL operations is called a transaction. All sql should run successfully or all should revert if any produces failure. Transaction embodies the ACID principle:
- Atomicity (all, or none)
- Consistency (cant save book-1 orders if no book-1 exists)
- Isolation (no other concurrent transaction should interfere in our transaction)
- Durability (assurance that our data are stored safely, e.g. across many DB systems)
- Local transactions: Application has one database to associate all transactions, usually with a JDBC connection
- Global transactions: Application spans across many databases, and a distributed DB management is applied, maybe through Java Transaction API (JTA)
- Yes it is
- A bean postprocessor of type InfrastructureAdvisorAutoProxyCreator acts on @Service and @Repository beans and creates proxies for @Transactional methods wrapping latter in an Around advice, first for initiating connections, and after for closing them.
- These proxies use TransactionInterceptor infrastructure bean and an implementation of PlatformTransactionManager (e.g. HibernateTransactionManager)
- Declaratively:
- @Configuration class with @EnableTransactionManagement
- Use @Transactional in method
- Programmatically:
- Use TransactionTemplate with a callback having our transaction logic
- Use PlatformTransactionManager along with TransactionDefinition and TransactionStatus
- Yes, by wrapping a Datasource in a proxy of type TransactionAwareDataSourceProxy, and using first to instantiate the JDBC Template
- Example:
- DataSource ds = new TransactionAwareDataSourceProxy(datasource);
JdbcTemplate template = new JdbcTemplate(ds);
- A level that is set per transaction, and refers to the degree of communication with other transactions operating on same data set
- There are 4 isolation levels, ordered as:
- READ_UNCOMMITTED
- Allows dirty reads (not yet committed), non-repeatable reads (reads that if repeated, may show altered row data) and phantom reads (reads that if repeated, may show same row data, but also more new rows)
- READ_COMMITTED
- Allows non-repeatable reads and phantom reads
- Doesn't allow dirty reads
- REPEATABLE_READ
- Allows phantom reads
- Doesn't allow dirty and non-repeatable reads
- SERIALIZABLE
- Allows none
Consider two transactions, T1
and T2
, are both dealing with a BankAccount entity with id=1
:
READ UNCOMMITTED:
T1
starts and updates thebalance
.T2
reads thebalance
whileT1
is still running.T2
sees the uncommitted changes ofT1
.READ COMMITTED:
T1
starts and updates thebalance
.T2
tries to read thebalance
beforeT1
commits.T2
will only see the committed balance, not the changes made byT1
untilT1
is committed.REPEATABLE READ:
T1
readsbalance
first. Meanwhile,T2
changes thebalance
and commits. IfT1
reads thebalance
again, it will see the same value as the first read, even ifT2
has committed a change.SERIALIZABLE: Both
T1
andT2
cannot run in parallel on the sameUser
entity (id=1
). They will be executed one after another, ensuring complete isolation.
- Enables transaction support in Spring
- Added in a @Configuration class
- Either registers a bean called txManager or PlatformTransactionManager by type, that developer provided with @Bean
- Defines a bean post-processor, that will act on @Service classes, looking for @Transactional method, to add proxy:
- Registers TransactionInterceptor
- Registers a JDK proxy
- In Spring Boot, it's not needed since spring-boot-starter-data-jpa dependency and a Datasource are declared.
- Example: @Transactional(propagation=Propagation.REQUIRED)
REQUIRES_NEW:
always create a new transaction (suspend existing, if any)NOT_SUPPORTED:
execute without transaction support, (suspend existing, if any)NEVER:
execute without transaction support, (exception, if any exists)REQUIRED
: use existing transaction (create new, if none exists)SUPPORTS:
use existing transaction if any, else run non-transactionallyMANDATORY
: if none already exists, throw exceptionNESTED:
if any exists, run extra nested transaction in it, else create a whole new one
- No extra proxy is created and no extra transaction
- Explanation: First, when a Bean @Transactional method is called, a proxy bean is created. Then, if our Bean calls itself (some other method), there is no need for an extra proxy bean. Transactions comply only with current PROPAGATED enums, and no new/extra is created.
- On class and method level
- Class level: define a default behavior (can alter specifically for each method with @Transactional)
- Class level: applies for all subclasses
- Method level: needs to be public
- Enable Spring transaction support with annotations, like @EnableTransactionManagement
- which enables a txManager/PlatformTransactionManager bean
- and @Transactional
- which enables proxy to handle the transaction basic jobs, like initiating/closing connection, and in-between execute our logic
- Transaction is rollbacked when any runtime exception occurs, by default
- Override with: rollbackForClassName, noRollbackFor, noRollbackForClassName
- Example 1: @Transactional(noRollbackFor=SomeCheckedOrUncheckedException.class)
- Example 2: @Transactional(rollbackForClassName="SomeCheckedOrUncheckedException"})
- By default, every test method will execute inside a transaction, and will rollback after completion
- Alter with @Commit on class/method level, and @Rollback(false) on method level
- Yes, within one @Transactional, already configured JpaTransactionManager (from Spring JPA) provides a transaction context on which we can interfere with e.g. JDBCTemplate / lower lever sql functions.
- JpaTransactionManager
- Serves one transaction context per resource
- JtaTransactionManager
- Servers one transaction context across multiple resources
- JPA with plain Spring:
- @Entities and CrudRepositories per entity
- @Configuration class with
- @EnableTransactionManagement
- PlatformTransactionManager bean
- LocalContainerEntityManagerFactoryBean / EntityManager
- DataSource bean
- JPA with Spring boot
- spring-boot-starter-data-jpa and all needed transitive dependencies
- Auto-configuration for JPA (PlatformTransactionManager, EntityManager, .. )
- Can configure datasource in properties file
- Support for Hikari connection pool
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
What may be missing, or could get better?