diff --git a/mybatis/mybatis.md b/mybatis/mybatis.md index 0a46f99..e47cfc9 100644 --- a/mybatis/mybatis.md +++ b/mybatis/mybatis.md @@ -937,3 +937,88 @@ foreach标签允许在动态sql中遍历集合,通常用于构建in条件。 ``` > 可以通过foreach执行便利操作,如果foreach指定的collection为array,那么index对应的时数组下标 > 若collection为map类型,那么index对应的是entry中的key,而value对应的是value + +## Java API +### SqlSession +SqlSession是Mybatis Java主要的接口,可以通过SqlSession来执行sql语句、获取Mapper实例、管理事务。 +### SqlSessionFactory +SqlSession实例是通过SqlSessionFactory方法来创建的,SqlSessionFactory对象包含创建SqlSession实例的各种方法。 +### SqlSessionFactoryBuilder +SqlSessionFactory本身是由SqlSessionFactoryBuilder来创建的,SqlSessionFactoryBuilder可以通过xml配置、注解或java配置代码来创建SqlSessionFactory。 +### SqlSessionFactoryBuilder详解 +SqlSessionFactoryBuilder有多个build方法,调用不同的build方法可以根据不同的资源创建SqlSessionFactory +```java +// 接受一个InputStream,该InputStream指向mybatis配置的xml文件 +// * environment参数是可选的,决定加载哪个环境,如果指定environment不存在,那么会抛出一个错误 +// 如果调用的build方法中没有environment参数,那么会使用默认的environment配置 +// * properties参数同样是可选的,如果调用的build方法制定了properties参数,那么properties参数中指定 +// 的属性可以在mybatis配置文件中使用,以${propertyName}的形式使用 +SqlSessionFactory build(InputStream inputStream) +SqlSessionFactory build(InputStream inputStream, String environment) +SqlSessionFactory build(InputStream inputStream, Properties properties) +SqlSessionFactory build(InputStream inputStream, String env, Properties props) +``` +> #### 配置文件中加载properties的优先顺序 +> * 在mybatis config配置文件的properties元素中指定的properties最先被加载 +> * 在properties元素的resouce属性或url属性中指定指定的properties文件中导入的属性其次加载,这次加载的properties属性会覆盖上一步中指定的属性 +> * 向build方法中传入的properties参数会最后被读取,并且覆盖之前所有的同名属性,具有最高的优先级 +> **故而,properties优先级顺序为“properties参数>url/resource属性指定的properties>properties元素体中指定的属性”** + +#### 创建SqlSessionFactory的示例 +```java +String resource = "org/mybatis/builder/mybatis-config.xml"; +InputStream inputStream = Resources.getResourceAsStream(resource); +SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); +SqlSessionFactory factory = builder.build(inputStream); +``` +#### 通过Configuration来创建SqlSessionFactory +之前在mybatis-config.xml中配置的所有mybatis配置属性都可以在Configuration中通过Java API来进行配置 +```java +DataSource dataSource = BaseDataTest.createBlogDataSource(); +TransactionFactory transactionFactory = new JdbcTransactionFactory(); + +Environment environment = new Environment("development", transactionFactory, dataSource); + +Configuration configuration = new Configuration(environment); +configuration.setLazyLoadingEnabled(true); +configuration.setEnhancementEnabled(true); +configuration.getTypeAliasRegistry().registerAlias(Blog.class); +configuration.getTypeAliasRegistry().registerAlias(Post.class); +configuration.getTypeAliasRegistry().registerAlias(Author.class); +configuration.addMapper(BoundBlogMapper.class); +configuration.addMapper(BoundAuthorMapper.class); + +SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); +SqlSessionFactory factory = builder.build(configuration); +``` +### SqlSessionFactory构建SqlSession实例 +SqlSessionFactory同样有多种方法来创建SqlSession实例 +- #### SqlSession openSession() +默认openSession()无参数的方法会创建具有如下特征的SqlSession +> 1. 事务作用域将会开启(自动提交关闭) +> 2. 从当前环境配置的Datasource中获取Connection +> 3. 事务的隔离级别将会使用驱动或者数据源的默认设置 +> 4. PreparedStatement(预处理语句)并不会被复用,也不会批量更新语句 + +- #### openSesion()的非空参方法 +```java +SqlSession openSession(boolean autoCommit) +SqlSession openSession(Connection connection) +SqlSession openSession(TransactionIsolationLevel level) +SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) +SqlSession openSession(ExecutorType execType) +SqlSession openSession(ExecutorType execType, boolean autoCommit) +SqlSession openSession(ExecutorType execType, Connection connection) +``` +#### openSession参数 +- autoCommit : boolean类型,为true则开启自动提交功能 +- connection :Connection类型,如果要使用自己的connection实例,可以将其传递给connection参数 +- level :TransactionIsolationLevel枚举类型,控制事务的隔离级别,可选的五个隔离级别为(NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE) +- ExecutorType :执行器类型 + - ExecutorType.SIMPLE:该类型的执行器为每个语句创建一个新的预处理语句(PreparedStatement) + - ExecutorType.REUSE:该类型的执行器会复用预处理语句 + - ExecutorType.BATCH:该类型的执行器会批量执行所有的更新语句,如果select语句位于多条update语句之间,那么必要时会将多条更新语句分割成不同的batch,以便于理解 +> #### batch(批量处理) +> batch会将相关的sql语句分组到一个batch文件中,并且一次提交到database server端。 +> - addBatch方法会将单独的sql语句添加到batch中,而executeBatch方法会执行batch中所有被分组到一起的sql语句 +> executeBatch方法会返回一个Integer数组,数组中每一个元素代表每个update语句的update count diff --git a/spring/Spring core/Spring Data Access.md b/spring/Spring core/Spring Data Access.md index 6c9ceb2..250994d 100644 --- a/spring/Spring core/Spring Data Access.md +++ b/spring/Spring core/Spring Data Access.md @@ -46,7 +46,7 @@ - rollbackFor: 默认情况下,@Transactional会针对unchecked异常和Error进行回滚操作 - transactionManager: 默认情况下,@Transactional注解会使用项目中默认的事务管理器(即bean name为transactionManager的事务管理器)。可以为@Transactional注解指定value属性或是transactionManager属性来指定想要采用的事务管理器的bean name或是qualifier - ## Transaction Propagation - - ### PROPAGATION_REQUIRED + - ### PROPAGATION.REQUIRED - 在Spring中,事务的传播行为默认是PROPAGATION_REQUIRED,默认情况下该选项会强制的要求一个物理事务 - 如果当前作用域中不存在事务,那么会创建一个新的事务 - 如果当前作用域的外层作用域已经存在事务,那么会加入到当前作用域的事务中去 @@ -54,11 +54,11 @@ > 如果想要对外层事务进行验证,可以手动将事务管理器的validateExistingTransaction属性设置为true。这样,当加入到一个隔离级别与内层事务完全不同的外层事务中时,该加入操作会被拒绝。在该设置下,如果read-write内层事务想要加入到外层的read-only事务中时,该加入操作也会被拒绝。 - 在事务传播行为被设置为PROPAGATION_REQUIRED的情况下,会为每个被设置事务的方法创建一个逻辑的事务作用域。各个逻辑事务作用域之间都是相互独立的,在不同逻辑事务作用域之间都可以独立设置事务的rollback-only属性。但是,在PROPAGATION_REQUIRED的情况下,内层事务和外层事务都映射到同一个物理事务,内层事务加入到外层事务中,故而在内层逻辑事务中为物理事务设置rollback-only会切实影响到外层事务的提交。 - 当事务传播行为被设置为PROPAGATION_REQUIRED时,如果内层事务设置了rollback-only标记,那么会导致外层物理事务的回滚。当外层事务尝试提交并失败回滚后,会抛出一个UnexceptedRollbackException异常,外层事务commit方法的调用者会接受到该UnexceptedRollbackException,代表内层发生了非预期的回滚操作 - - ### PROPAGATION_NEW - - 相对于PROPAGATION_REQUIRED,PROPAGATION_NEW传播行为会一直使用独立的物理事务,而不会尝试区加入外部已经存在的物理事务。 + - ### PROPAGATION.REQUIRES_NEW + - 相对于PROPAGATION_REQUIRED,PROPAGATION.REQUIRES_NEW传播行为会一直使用独立的物理事务,而不会尝试区加入外部已经存在的物理事务。 - 对于PROPAGATION_NEW,其内层事务和外层事务都可以独立的提交或回滚,内层事务的回滚并不会导致外层事务的回滚。 - - 将事务传播行为设置为PROPAGATION_NEW时,内层事务可以独立定义自己的隔离级别、timeout值、read-only属性,而不必继承外部事务的这些属性。在PROPAGATION_REQUIRED中,内部事务自定义这些属性将会被忽略,内部事务加入外部事务后会采用外部事务的设置。 - - ### PROPAGATION_NESTED + - 将事务传播行为设置为PROPAGATION.REQUIRES_NEW时,内层事务可以独立定义自己的隔离级别、timeout值、read-only属性,而不必继承外部事务的这些属性。在PROPAGATION_REQUIRED中,内部事务自定义这些属性将会被忽略,内部事务加入外部事务后会采用外部事务的设置。 + - ### PROPAGATION.NESTED - 和PROPAGATION_REQUIRED类似,PROPAGATION_NESTED同样也只有一个物理事务。但是其支持多个savepoint(存档点),该物理事务可以回滚到特定的存档点而非必须回滚整个事务。 - 由于PROPAGATION_NESTED对存档点的支持,故而在PROPAGATION_NESTED条件下,可以进行部分回滚。内层事务的回滚操作并不会造成外部事务的回滚,内层事务回滚后外层事务仍然能够继续执行和提交。 > 由于PROPAGATION_NESTED需要JDBC savepoint(存档点)的支持,故而该设置仅仅对JDBC事务资源有效。