spring整合mybatis事务案例首先 需要下载需要的sql：sql下载案例目录结构 1.实体类和jdbc.properties文件 2.dao层编写 3.service层接口和实现 4.config目录下编写 5.注解测试UserServiceTest运行 pom.xml 1.实体类和jdbc.properties文件package com.limei.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } } <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.limei.aop</groupId> <artifactId>Spring_aop</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency> </dependencies> </project>2.dao层编写package com.limei.dao; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Update; import java.util.List; public interface AccountDao { /** * 入账操作 * @param name 入账用户名 * @param money 入账金额 */ @Update("update account set money = money + #{money} where name = #{name}") void inMoney(@Param("name") String name, @Param("money") Double money); /** * 出账操作 * @param name 出账用户名 * @param money 出账金额 */ @Update("update account set money = money - #{money} where name = #{name}") void outMoney(@Param("name") String name, @Param("money") Double money); } 3.service层接口和实现package com.limei.service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.List; @Transactional(isolation = Isolation.DEFAULT) public interface AccountService { /** * 转账操作 * @param outName 出账用户名 * @param inName 入账用户名 * @param money 转账金额 */ @Transactional( readOnly = false, timeout = -1, isolation = Isolation.DEFAULT, rollbackFor = {}, noRollbackFor = {}, propagation = Propagation.REQUIRES_NEW ) public void transfer(String outName, String inName, Double money); } package com.limei.service.impl; import com.limei.dao.AccountDao; import com.limei.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; /** * 转账操作 * * @param outName 出账用户名 * @param inName 入账用户名 * @param money 转账金额 */ public void transfer(String outName, String inName, Double money) { accountDao.inMoney ( outName,money); int i=1/0; accountDao.outMoney ( inName,money ); } } 4.config目录下编写package com.limei.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @ComponentScan("com.limei") @PropertySource("classpath:jdbc.properties") @Import({JDBCConfig.class,MyBatisConfig.class}) @EnableTransactionManagement public class SpringConfig { } package com.limei.config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; public class MyBatisConfig { @Bean public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.limei.domain"); ssfb.setDataSource(dataSource); return ssfb; } @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.limei.dao"); return msc; } } package com.limei.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; public class JDBCConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } @Bean public PlatformTransactionManager getTransactionManager(DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } } 5.注解测试UserServiceTest运行 package com.limei.service; import com.limei.config.SpringConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; //设定spring专用的类加载器 @RunWith(SpringJUnit4ClassRunner.class) //设定加载的spring上下文对应的配置 @ContextConfiguration(classes = SpringConfig.class) public class UserServiceTest { @Autowired private AccountService accountService; @Test public void testTransfer(){ accountService.transfer ( "张三","李四",100D ); } }6.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.limei.aop</groupId> <artifactId>Spring_aop</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency> </dependencies> </project>
1.事物的介绍 2.事务管理 3.事务控制案例(编程式) 4.aop改造事务(编程式) 5.声明式事务(XML格式) 6.tx-method的详解和传播行为 7.声明式事务改造(注解) 1.事物的介绍1.1 什么是事务？事务指数据库中多个操作合并在一起形成的操作序列1.2事务的作用1.当数据库操作序列中个别操作失败时，提供一种方式使数据库状态恢复到正常状态（A），保障数据库即使在异常状态下仍能保持数据一致性（C）（要么操作前状态，要么操作后状态）。2.当出现并发访问数据库时，在多个访问间进行相互隔离，防止并发访问操作结果互相干扰（I）。事务特征（ACID）原子性（Atomicity）指事务是一个不可分割的整体，其中的操作要么全执行或全不执行一致性（Consistency）事务前后数据的完整性必须保持一致隔离性（Isolation）事务的隔离性是多个用户并发访问数据库时，数据库为每一个用户开启的事务，不能被其他事务的操作数据所干扰，多个并发事务之间要相互隔离持久性（Durability）持久性是指一个事务一旦被提交，它对数据库中数据的改变就是永久性的，接下来即使数据库发生故障也不应该对其有任何影响1.3事务的隔离级脏读：允许读取未提交的信息原因：Read uncommitted-解决方案： （表级读锁）不可重复读：读取过程中单个数据发生了变化解决方案： Repeatable read （行级写锁）幻读：读取过程中数据条目发生了变化解决方案： Serializable（表级写锁）2.事物管理2.1Spring事务核心对象J2EE开发使用分层设计的思想进行，对于简单的业务层转调数据层的单一操作，事务开启在业务层或者数据层并无太大差别，当业务中包含多个数据层的调用时，需要在业务层开启事务，对数据层中多个操作进行组合并归属于同一个事务进行处理Spring为业务层提供了整套的事务解决方案PlatformTransactionManagerTransactionDefinitionTransactionStatus2.2 PlatformTransactionManager平台事务管理器实现类DataSourceTransactionManager 适用于Spring JDBC或MyBatisHibernateTransactionManager 适用于Hibernate3.0及以上版本JpaTransactionManager 适用于JPAJdoTransactionManager 适用于JDOJtaTransactionManager 适用于JTAJPA（Java Persistence API）Java EE 标准之一，为POJO提供持久化标准规范，并规范了持久化开发的统一API，符合JPA规范的开发可以在不同的JPA框架下运行JDO(Java Data Object )是Java对象持久化规范，用于存取某种数据库中的对象，并提供标准化API。与JDBC相比，JDBC仅针对关系数据库进行操作，JDO可以扩展到关系数据库、文件、XML、对象数据库（ODBMS）等，可移植性更强JTA（Java Transaction API）Java EE 标准之一，允许应用程序执行分布式事务处理。与JDBC相比，JDBC事务则被限定在一个单一的数据库连接，而一个JTA事务可以有多个参与者，比如JDBC连接、JDO 都可以参与到一个JTA事务中此接口定义了事务的基本操作获取事务 ：TransactionStatus getTransaction(TransactionDefinition definition)提交事务 ：void commit(TransactionStatus status) 回滚事务 ：void rollback(TransactionStatus status)2.3 TransactionDefinition此接口定义了事务的基本信息获取事务定义名称String getName()获取事务的读写属性boolean isReadOnly()获取事务隔离级别int getIsolationLevel()获事务超时时间int getTimeout()获取事务传播行为特征int getPropagationBehavior()2.4 TransactionStatus此接口定义了事务在执行过程中某个时间点上的状态信息及对应的状态操作3.事务控制案例(编程式)首先 需要下载需要的sql：sql下载案例目录结构银行转账业务说明:银行转账操作中，涉及从A账户到B账户的资金转移操作。数据层仅提供单条数据的基础操作，未设计多账户间的业务操作。 实体类和jdbc的编写 dao层和AccountDao.xml编写 service层编写 app的编写 applicationContext.xml编写 pom.xml 实体类和jdbc的编写package com.limei.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } } jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/lianxi jdbc.username=root jdbc.password=123456dao层和AccountDao.xml编写package com.limei.dao; import org.apache.ibatis.annotations.Param; import java.util.List; public interface AccountDao { /** * 入账操作 * @param name 入账用户名 * @param money 入账金额 */ void inMoney(@Param("name") String name, @Param("money") Double money); /** * 出账操作 * @param name 出账用户名 * @param money 出账金额 */ void outMoney(@Param("name") String name, @Param("money") Double money); } <?xml version="1.0" encoding="UTF-8"?> <mapper namespace="com.limei.dao.AccountDao"> <update id="inMoney"> update account set money = money + #{money} where name = #{name} </update> <update id="outMoney"> update account set money = money - #{money} where name = #{name} </update> </mapper>service层编写package com.limei.service; import java.util.List; public interface AccountService { /** * 转账操作 * @param outName 出账用户名 * @param inName 入账用户名 * @param money 转账金额 */ public void transfer(String outName, String inName, Double money); } package com.limei.service.impl; import com.limei.dao.AccountDao; import com.limei.domain.Account; import com.limei.service.AccountService; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import javax.sql.DataSource; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void transfer(String outName, String inName, Double money) { //开启事务 PlatformTransactionManager ptm = new DataSourceTransactionManager (dataSource); //事务定义 TransactionDefinition td = new DefaultTransactionDefinition (); //事务状态 TransactionStatus ts = ptm.getTransaction(td); accountDao.inMoney(outName,money); int i = 1/0; accountDao.outMoney(inName,money); //提交事务 ptm.commit(ts); } }aop的编写import com.limei.service.AccountService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml"); AccountService accountService = (AccountService) ctx.getBean("accountService"); accountService.transfer("李四","张三",100D); } }applicationContext.xml编写<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:property-placeholder location="classpath:*.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="accountService" class="com.limei.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="dataSource" ref="dataSource"/> </bean> <bean class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.limei.domain"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.limei.dao"/> </bean> </beans>pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.limei.aop</groupId> <artifactId>Spring_aop</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> </dependencies> </project>4.aop改造事务(编程式)使用AOP控制事务将业务层的事务处理功能抽取出来制作成AOP通知，利用环绕通知运行期动态织入。在limei下创建aop,然后在aop下创建TxAdvice类。package com.limei.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import javax.sql.DataSource; public class TxAdvice { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public Object transactionManager(ProceedingJoinPoint pjp) throws Throwable { //开启事务 PlatformTransactionManager ptm = new DataSourceTransactionManager(dataSource); //事务定义 TransactionDefinition td = new DefaultTransactionDefinition(); //事务状态 TransactionStatus ts = ptm.getTransaction(td); Object ret = pjp.proceed(pjp.getArgs()); //提交事务 ptm.commit(ts); return ret; } } }配置AOP通知类，并注入dataSource。<bean id="txAdvice" class="com.itheima.aop.TxAdvice"> <property name="dataSource" ref="dataSource"/> </bean>使用环绕通知将通知类织入到原始业务对象执行过程中<aop:config> <aop:pointcut id="pt" expression="execution(* *..transfer(..))"/> <aop:aspect ref="txAdvice"> <aop:around method="tx" pointcut-ref="pt"/> </aop:aspect> </aop:config>5.声明式事务(XML格式)在事务控制案例中的 applicationContext.xml中增加以下配置： <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" read-only="false" /> <tx:method name="get*" read-only="true" /> <tx:method name="find*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pt" expression="execution(* com.limei.service.*Service.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config>aop:advice与aop:advisor区别aop:advice配置的通知类可以是普通java对象，不实现接口，也不使用继承关系aop:advisor配置的通知类必须实现通知接口MethodBeforeAdviceAfterReturningAdviceThrowsAdvice6.tx-method的详解和传播行为tx配置----tx:method事务的传播行为7.声明式事务改造(注解)可以在上述AccountService接口中 添加事务，替换applicationContext.xml 中的事务@Transactional名称：@Transactional类型：方法注解，类注解，接口注解位置：方法定义上方，类定义上方，接口定义上方作用：设置当前类/接口中所有方法或具体方法开启事务，并指定相关事务属性范例：@Transactional( readOnly = false, timeout = -1, isolation = Isolation.DEFAULT, rollbackFor = {ArithmeticException.class, IOException.class}, noRollbackFor = {}, propagation = Propagation.REQUIRES_NEW )tx:annotation-driven在applicationContext.xml中添加下面这段代码名称：tx:annotation-driven类型：标签归属：beans标签作用：开启事务注解驱动，并指定对应的事务管理器范例：<tx:annotation-driven transaction-manager="txManager"/>
1.AOP的配置 2.AOP的注解驱动 3.综合案例 AOP的配置注解开发AOP制作步骤在XML格式基础上导入坐标（伴随spring-context坐标导入已经依赖导入完成）开启AOP注解支持配置切面@Aspect定义专用的切入点方法，并配置切入点@Pointcut为通知方法配置通知类型及对应切入点@Before注解开发AOP注意事项1.切入点最终体现为一个方法，无参无返回值，无实际方法体内容，但不能是抽象方法2.引用切入点时必须使用方法调用名称，方法后面的（）不能省略3.切面类中定义的切入点只能在当前类中使用，如果想引用其他类中定义的切入点使用“类名.方法名()”引用4.可以在通知类型注解后添加参数，实现XML配置中的属性，例如after-returning后的returning属性AOP的注解驱动AOP注解驱动名称：@EnableAspectJAutoProxy类型：注解位置：Spring注解配置类定义上方作用：设置当前类开启AOP注解驱动的支持，加载AOP注解格式：@Configuration @ComponentScan("com.limei") @EnableAspectJAutoProxy public class SpringConfig { }综合案例首先 需要下载需要的sql：sql下载案例目录结构 实体类和jdbc的编写 config编写 dao层编写 service层编写 aop的编写 测试类编写 pom.xml 实体类和jdbc的编写package com.limei.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } } jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/lianxi jdbc.username=root jdbc.password=123456config编写package com.limei.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; public class JDBCConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } } package com.limei.config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; public class MyBatisConfig { @Bean public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.limei.domain"); ssfb.setDataSource(dataSource); return ssfb; } @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.limei.dao"); return msc; } } package com.limei.config; import com.limei.aop.RunTimeMonitorAdvice; import com.limei.config.JDBCConfig; import com.limei.config.MyBatisConfig; import org.springframework.context.annotation.*; @Configuration @ComponentScan ( "com" ) @PropertySource("classpath:jdbc.properties") @Import({JDBCConfig.class, MyBatisConfig.class}) @EnableAspectJAutoProxy public class SpringConfig { }dao层编写package com.limei.dao; import com.limei.domain.Account; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; public interface AccountDao { @Insert("insert into account(name,money)values(#{name},#{money})") void save(Account account); @Delete("delete from account where id = #{id} ") void delete(Integer id); @Update("update account set name = #{name} , money = #{money} where id = #{id} ") void update(Account account); @Select("select * from account") List<Account> findAll(); @Select("select * from account where id = #{id}") Account findById(Integer id); }service层编写package com.limei.service; import com.limei.domain.Account; import java.util.List; public interface AccountService { void save(Account account); void delete(Integer id); void update(Account account); List<Account> findAll(); Account findById(Integer id); } package com.limei.service.impl; import com.limei.dao.AccountDao; import com.limei.domain.Account; import com.limei.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void save(Account account) { accountDao.save(account); } public void update(Account account){ accountDao.update(account); } public void delete(Integer id) { accountDao.delete(id); } public Account findById(Integer id) { return accountDao.findById(id); } public List<Account> findAll() { return accountDao.findAll(); } } aop的编写package com.limei.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class RunTimeMonitorAdvice { //切入点，监控业务层接口 @Pointcut("execution(* com.limei.service.*Service.find*(..))") public void pt(){ } @Around("pt()") public Object runtimeAround(ProceedingJoinPoint pjp) throws Throwable { //获取执行签名信息 Signature signature = pjp.getSignature(); //通过签名获取执行类型（接口名） String className = signature.getDeclaringTypeName(); //通过签名获取执行操作名称（方法名） String methodName = signature.getName(); //原始方法的调用 Object ret=pjp.proceed (pjp.getArgs ()); //执行时长累计值 long sum = 0L; for (int i = 0; i < 10000; i++) { //获取操作前系统时间beginTime long startTime = System.currentTimeMillis(); //原始操作调用 pjp.proceed(pjp.getArgs()); //获取操作后系统时间endTime long endTime = System.currentTimeMillis(); sum += endTime-startTime; } //打印信息 System.out.println(className+":"+methodName+" (万次）run:"+sum+"ms"); return ret; } } 测试类编写package com.limei.service; import com.limei.config.SpringConfig; import com.limei.domain.Account; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; //设定spring专用的类加载器 @RunWith(SpringJUnit4ClassRunner.class) //设定加载的spring上下文对应的配置 @ContextConfiguration(classes = SpringConfig.class) public class UserServiceTest { @Autowired private AccountService accountService; @Test public void testFindById(){ Account ac = accountService.findById(1); System.out.println(ac); } @Test public void testFindAll(){ List<Account> list = accountService.findAll(); // System.out.println(list); } } pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.limei.aop</groupId> <artifactId>Spring_aop</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency> </dependencies> </project>
1.AOP的简介 2.AOP相关概念 3.AOP的通知类型5种 4.AOP入门案例 AOP的简介AOP(Aspect Oriented Programing)面向切面编程，一种编程范式，隶属于软工范畴，指导开发者如何组织程序结构AOP弥补了OOP的不足，基于OOP基础之上进行横向开发uOOP规定程序开发以类为主体模型，一切围绕对象进行，完成某个任务先构建模型uAOP程序开发主要关注基于OOP开发中的共性功能，一切围绕共性功能进行，完成某个任务先构建可能遇到的所有共性功能（当所有功能都开发出来也就没有共性与非共性之分）AOP作用伴随着AOP时代的降临，可以从各个行业的标准化、规范化开始入手，一步一步将所有共性功能逐一开发完毕，最终以功能组合来完成个别业务模块乃至整体业务系统的开发目标：将软件开发由手工制作走向半自动化/全自动化阶段，实现“插拔式组件体系结构”搭建AOP优势提高代码的可重用性业务代码编码更简洁业务代码维护更高效业务功能扩展更便捷AOP的相关概念Joinpoint(连接点)：就是方法Pointcut(切入点)：就是挖掉共性功能的方法Advice(通知)：就是共性功能，最终以一个方法的形式呈现Aspect(切面)：就是共性功能与挖的位置的对应关系Target(目标对象)：就是挖掉功能的方法对应的类产生的对象，这种对象是无法直接完成最终工作的Weaving(织入)：就是将挖掉的功能回填的动态过程Proxy(代理)：目标对象无法直接完成工作，需要对其进行功能回填，通过创建原始对象的代理对象实现Introduction(引入/引介) ：就是对原始对象无中生有的添加成员变量或成员方法AOP开发过程开发阶段(开发者完成)正常的制作程序将非共性功能开发到对应的目标对象类中，并制作成切入点方法将共性功能独立开发出来，制作成通知在配置文件中，声明切入点在配置文件中，声明切入点与通知间的关系（含通知类型），即切面运行阶段(AOP完成)Spring容器加载配置文件，监控所有配置的切入点方法的执行当监控到切入点方法被运行，使用代理机制，动态创建目标对象的代理对象，根据通知类别，在代理对象的对应位置将通知对应的功能织入，完成完整的代码逻辑并运行AOP的通知类型5种前置通知：原始方法执行前执行，如果通知中抛出异常，阻止原始方法运行应用：数据校验格式：<aop:aspect ref="adviceId"> <aop:before method="methodName" pointcut="……"/> </aop:aspect>说明：一个aop:aspect标签中可以配置多个aop:before标签基本属性：method ：在通知类中设置当前通知类别对应的方法pointcut ：设置当前通知对应的切入点表达式，与pointcut-ref属性冲突pointcut-ref ：设置当前通知对应的切入点id，与pointcut属性冲突后置通知：原始方法执行后执行，无论原始方法中是否出现异常，都将执行通知 应用：现场清理格式：<aop:aspect ref="adviceId"> <aop:after method="methodName" pointcut="……"/> </aop:aspect>说明：一个aop:aspect标签中可以配置多个aop:after标签返回后通知：原始方法正常执行完毕并返回结果后执行，如果原始方法中抛出异常，无法执行 应用：返回- 格式：<aop:aspect ref="adviceId"> <aop:after-returning method="methodName" pointcut="……"/> </aop:aspect>说明：一个aop:aspect标签中可以配置多个aop:after-returning标签值相关数据处理抛出异常后通知：原始方法抛出异常后执行，如果原始方法没有抛出异常，无法执行 应用：对原始方法中出现的异常信息进行处理格式：<aop:aspect ref="adviceId"> <aop:after-throwing method="methodName" pointcut="……"/> </aop:aspect>说明：一个aop:aspect标签中可以配置多个aop:after-throwing标签环绕通知：在原始方法执行前后均有对应执行执行，还可以阻止原始方法的执行 应用：十分强大，可以做任何事情格式：<aop:aspect ref="adviceId"> <aop:around method="methodName" pointcut="……"/> </aop:aspect>说明：一个aop:aspect标签中可以配置多个aop:around标签环绕通知的开发方式环绕通知是在原始方法的前后添加功能，在环绕通知中，存在对原始方法的显式调用public Object around(ProceedingJoinPoint pjp) throws Throwable { Object ret = pjp.proceed(); return ret; }环绕通知方法相关说明：方法须设定Object类型的返回值，否则会拦截原始方法的返回。如果原始方法返回值类型为void，通知方 也可以设定返回值类型为void，最终返回null方法需在第一个参数位置设定ProceedingJoinPoint对象，通过该对象调用proceed()方法，实现对原始方法的调用。如省略该参数，原始方法将无法执行使用proceed()方法调用原始方法时，因无法预知原始方法运行过程中是否会出现异常，强制抛出Throwable对象，封装原始方法中可能出现的异常信息AOP的入门案例案例目录结构 接口和接口实现类 AOP的通知类 xml配置 启动类 接口和接口实现类编写package com.limei.service; public interface UserService { public void save(int i,int m ); } package com.limei.service.impl; import com.limei.service.UserService; public class UserServiceImpl implements UserService { public void save(int i,int m) { //0.将共性功能抽取出来 //System.out.println("共性功能"); System.out.println("user service running..."+i+","+m); } } AOP的通知类package com.limei.aop; import org.aspectj.lang.JoinPoint; public class AOPAdvice { public void function(JoinPoint jp){ Object[] args = jp.getArgs (); System.out.println("共性功能。。。"+args[0]); } public void before(int x,int y){ System.out.println ("before..."+x+","+y); } } xml配置<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.limei.service.impl.UserServiceImpl"/> <bean id="myAdvice" class="com.limei.aop.AOPAdvice"/> <aop:config> <aop:pointcut id="pt" expression="execution(* *..*(..))"/> <aop:aspect ref="myAdvice"> <aop:before method="function" pointcut-ref="pt"/> <aop:before method="before" pointcut="execution(* *..*(int,int))&&args(x,y)"></aop:before> </aop:aspect> </aop:config> </beans>启动类import com.limei.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ( "applicationContext.xml" ); UserService userService = (UserService) ctx.getBean ( "userService" ); userService.save (666,777); } }
spring整合mybatis案例首先需要sql：sql结构下载。 1.实体类和jdbc.properties文件 2.编写业务层接口与实现类 3.编写数据层接口 4.编写原来的xml为注解方式 5.main方法运行 6.注解测试UserServiceTest运行 案例目录结构实体类Accountpackage com.limei.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } } jdbc.propertiesjdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/lianxi jdbc.username=root jdbc.password=1234562.编写业务层接口与实现类package com.limei.service; import com.limei.domain.Account; import java.util.List; public interface AccountService { void save(Account account); void delete(Integer id); void update(Account account); List<Account> findAll(); Account findById(Integer id); } package com.limei.service.impl; import com.limei.dao.AccountDao; import com.limei.domain.Account; import com.limei.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; public void save(Account account) { accountDao.save(account); } public void update(Account account){ accountDao.update(account); } public void delete(Integer id) { accountDao.delete(id); } public Account findById(Integer id) { return accountDao.findById(id); } public List<Account> findAll() { return accountDao.findAll(); } } 3.编写数据层接口package com.limei.dao; import com.limei.domain.Account; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; public interface AccountDao { @Insert("insert into account(name,money)values(#{name},#{money})") void save(Account account); @Delete("delete from account where id = #{id} ") void delete(Integer id); @Update("update account set name = #{name} , money = #{money} where id = #{id} ") void update(Account account); @Select("select * from account") List<Account> findAll(); @Select("select * from account where id = #{id} ") Account findById(Integer id); }4.编写原来的xml为注解方式package com.limei.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; public class JDBCConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } } .package com.limei.config; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; public class MyBatisConfig { @Bean public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){ SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.limei.domain"); ssfb.setDataSource(dataSource); return ssfb; } @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.limei.dao"); return msc; } } package com.limei.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource; @Configuration @ComponentScan("com.limei") @PropertySource("classpath:jdbc.properties") @Import({JDBCConfig.class,MyBatisConfig.class}) public class SpringConfig { }5.main方法运行Test.javaimport com.limei.config.SpringConfig; import com.limei.domain.Account; import com.limei.service.AccountService; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test { public static void main(String[] args) { // ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // AccountService accountService = (AccountService) ctx.getBean("accountService"); // Account ac = accountService.findById(2); // System.out.println(ac); ApplicationContext ctx = new AnnotationConfigApplicationContext ( SpringConfig.class); AccountService accountService = (AccountService) ctx.getBean("accountService"); Account ac = accountService.findById(2); System.out.println(ac); } }6.注解测试UserServiceTest运行package limei.service; import com.limei.config.SpringConfig; import com.limei.domain.Account; import com.limei.service.AccountService; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; //设定spring专用的类加载器 @RunWith(SpringJUnit4ClassRunner.class) //设定加载的spring上下文对应的配置 @ContextConfiguration(classes = SpringConfig.class) public class UserServiceTest { @Autowired private AccountService accountService; @Test public void testFindById(){ Account ac = accountService.findById(2); // System.out.println(ac); Assert.assertEquals("李四",ac.getName()); } @Test public void testFindAll(){ List<Account> list = accountService.findAll(); Assert.assertEquals(7,list.size()); } }
bean的定义 bean的作用域 bean的生命周期 @Bean加载第三方资源 bean的非引用类型属性注入 bean的引用类型属性注入 注解加载properties文件 @Configuration和@ComponentScan用法 第三方bean配置与管理 bean加载控制 bean的定义名称：@Component @Controller @Service @Repository类型：类注解位置：类定义上方作用：设置该类为spring管理的bean范例：@Component public class ClassName{}说明：@Controller、@Service 、@Repository是@Component的衍生注解，功能同@Component相关属性value（默认）：定义bean的访问idbean的作用域名称：@Scope类型：类注解位置：类定义上方作用：设置该类作为bean对应的scope属性范例：@Scope public class ClassName{}相关属性value（默认）：定义bean的作用域，默认为singletonbean的生命周期名称：@PostConstruct、@PreDestroy类型：方法注解位置：方法定义上方作用：设置该类作为bean对应的生命周期方法范例：@PostConstruct public void init() { System.out.println("init..."); }@Bean加载第三方资源类型：方法注解位置：方法定义上方作用：设置该方法的返回值作为spring管理的bean范例：@Bean("dataSource") public DruidDataSource createDataSource() { return ……; }说明：因为第三方bean无法在其源码上进行修改，使用@Bean解决第三方bean的引入问题该注解用于替代XML配置中的静态工厂与实例工厂创建bean，不区分方法是否为静态或非静态@Bean所在的类必须被spring扫描加载，否则该注解无法生效相关属性value（默认）：定义bean的访问idbean的非引用类型属性注入名称：@Value类型：属性注解、方法注解位置：属性定义上方，方法定义上方作用：设置对应属性的值或对方法进行传参范例：@Value("${jdbc.username}") private String username;说明：value值仅支持非引用类型数据，赋值时对方法的所有参数全部赋值value值支持读取properties文件中的属性值，通过类属性将properties中数据传入类中value值支持SpEL@value注解如果添加在属性上方，可以省略set方法（set方法的目的是为属性赋值）相关属性value（默认）：定义对应的属性值或参数值bean的引用类型属性注入1.名称：@Autowired、@Qualifier类型：属性注解、方法注解位置：属性定义上方，方法定义上方作用：设置对应属性的对象或对方法进行引用类型传参范例：@Autowired(required = false) @Qualifier("userDao") private UserDao userDao;说明：@Autowired默认按类型装配，指定@Qualifier后可以指定自动装配的bean的id相关属性required：定义该属性是否允许为null2.名称：@Primary类型：类注解位置：类定义上方作用：设置类对应的bean按类型装配时优先装配范例：@Primary public class ClassName{}说明：@Autowired默认按类型装配，当出现相同类型的bean，使用@Primary提高按类型自动装配的优先级，多个@Primary会导致优先级设置无效3.名称：@Inject、@Named、@Resource说明：@Inject与@Named是JSR330规范中的注解，功能与@Autowired和@Qualifier完全相同，适用于不同架构场景@Resource是JSR250规范中的注解，可以简化书写格式@Resource相关属性name：设置注入的bean的idtype：设置注入的bean的类型，接收的参数为Class类型加载properties文件名称：@PropertySource类型：类注解位置：类定义上方作用：加载properties文件中的属性值范例：@PropertySource(value = "classpath:filename.properties") public class ClassName { @Value("${propertiesAttributeName}") private String attributeName; }说明：不支持*通配格式，一旦加载，所有spring控制的bean中均可使用对应属性值相关属性value（默认）：设置加载的properties文件名ignoreResourceNotFound：如果资源未找到，是否忽略，默认为false@Configuration和@ComponentScan用法名称：@Configuration、@ComponentScan类型：类注解位置：类定义上方作用：设置当前类为spring核心配置加载类范例：@Configuration @ComponentScan("scanPackageName") public class SpringConfigClassName{ }说明：核心配合类用于替换spring核心配置文件，此类可以设置空的，不设置变量与属性bean扫描工作使用注解@ComponentScan替代AnnotationConfigApplicationContext加载纯注解格式上下文对象，需要使用AnnotationConfigApplicationContextAnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);第三方bean配置与管理名称：@Import类型：类注解位置：类定义上方作用：导入第三方bean作为spring控制的资源范例：@Import({JDBCConfig.class,MyBatisConfig.class}) public class SpringConfig { }说明：@Import注解在同一个类上，仅允许添加一次，如果需要导入多个，使用数组的形式进行设定在被导入的类中可以继续使用@Import导入其他资源（了解）@Bean所在的类可以使用导入的形式进入spring容器，无需声明为beanbean加载控制(1)@DependsOn名称：@DependsOn类型：类注解、方法注解位置：bean定义的位置（类上或方法上）作用：控制bean的加载顺序，使其在指定bean加载完毕后再加载范例：@DependsOn("beanId") public class ClassName { }说明：配置在方法上，使@DependsOn指定的bean优先于@Bean配置的bean进行加载配置在类上，使@DependsOn指定的bean优先于当前类中所有@Bean配置的bean进行加载配置在类上，使@DependsOn指定的bean优先于@Component等配置的bean进行加载相关属性value（默认）：设置当前bean所依赖的bean的id(2)@Order名称：@Order类型：配置类注解位置：配置类定义的位置（类上）作用：控制配置类的加载顺序范例：@Order(1) public class SpringConfigClassName { }(3)@Lazy名称：@Lazy类型：类注解、方法注解位置：bean定义的位置（类上或方法上）作用：控制bean的加载时机，使其延迟加载范例：@Lazy public class ClassName { }依赖加载应用场景@DependsOn微信订阅号，发布消息和订阅消息的bean的加载顺序控制双11活动期间，零点前是结算策略A，零点后是结算策略B，策略B操作的数据为促销数据。策略B加载顺序与促销数据的加载顺序@Lazy程序灾难出现后对应的应急预案处理是启动容器时加载时机@Order多个种类的配置出现后，优先加载系统级的，然后加载业务级的，避免细粒度的加载控制
spring整合mybatis案例首先需要sql：sql结构下载。 1.坐标pom.xml文件和实体类 2.编写业务层接口与实现类 3.编写持久层接口与对应的xml文件 4.建立applicationContext.xml配置文件 5.jdbc.properties资源 6.Test类 案例目录结构1.pom.xml文件<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>java-01</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> </dependencies> </project>package com.limei.domain; import java.io.Serializable; public class Account implements Serializable { private Integer id; private String name; private Double money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } } 2.编写业务层接口与实现类package com.limei.service; import com.limei.domain.Account; import java.util.List; public interface AccountService { void save(Account account); void delete(Integer id); void update(Account account); List<Account> findAll(); Account findById(Integer id); } package com.limei.service.impl; import com.limei.dao.AccountDao; import com.limei.domain.Account; import com.limei.service.AccountService; import java.util.List; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void save(Account account) { accountDao.save(account); } public void update(Account account){ accountDao.update(account); } public void delete(Integer id) { accountDao.delete(id); } public Account findById(Integer id) { return accountDao.findById(id); } public List<Account> findAll() { return accountDao.findAll(); } } 3.编写持久层接口与对应的xml文件package com.limei.dao; import com.limei.domain.Account; import java.util.List; public interface AccountDao { void save(Account account); void delete(Integer id); void update(Account account); List<Account> findAll(); Account findById(Integer id); } <?xml version="1.0" encoding="UTF-8"?> <mapper namespace="com.limei.dao.AccountDao"> select * from account where id = #{id} select * from account <insert id="save" parameterType="account"> insert into account(name,money)values(#{name},#{money}) </insert> <delete id="delete" parameterType="int"> delete from account where id = #{id} </delete> <update id="update" parameterType="account"> update account set name=#{name},money=#{money} where id=#{id} </update> </mapper>4.建立applicationContext.xml配置文件<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:*.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="accountService" class="com.limei.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean> <bean class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.limei.domain"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.limei.dao"/> </bean> </beans>5.jdbc.properties资源jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/lianxi jdbc.username=root jdbc.password=1234566.Test类import com.limei.domain.Account; import com.limei.service.AccountService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml"); AccountService accountService = (AccountService) ctx.getBean("accountService"); Account ac = accountService.findById(3); System.out.println(ac); // Account account = new Account(); // account.setName("Tom"); // account.setMoney(123456.78); // // accountService.save(account); } }
IoC入门案例制作步骤 1.spring坐标pom.xml文件 2.编写业务层接口与实现类 3.编写持久层接口与实现类 4.建立spring配置文件 5.data.properties资源 6.TestUser测试类通过spring获取资源（Service实例） 案例目录结构1.pom.xml文件<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>java-01</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>2.编写业务层与表现层（模拟）接口与实现类package com.limei.service; public interface UserService { public void save(); } package com.limei.service.impl; import com.limei.dao.UserDao; import com.limei.service.UserService; public class UserServiceImpl implements UserService { public UserServiceImpl() { } private UserDao userDao; private int num; public void setNum(int num) { this.num = num; } //1.对需要进行注入的变量加set方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save() { System.out.println("user service running..."+num); userDao.save(); } } 3.编写持久层层接口与实现类 package com.limei.dao; public interface UserDao { public void save(); } package com.limei.dao.impl; import com.limei.dao.UserDao; public class UserDaoImpl implements UserDao{ private String userName; private String password; private int num; private String name; public UserDaoImpl() { } public void setNum(int num) { this.num = num; } public void setUserName(String userName) { this.userName = userName; } public void setPassword(String password) { this.password = password; } public void setName(String name) { this.name = name; } public void save(){ System.out.println("user dao running..."+userName+" "+password+" "+num ); } } 4.建立spring配置文件applicationContext.xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:data.properties" /> <bean id="userDao" class="com.limei.dao.impl.UserDaoImpl" > <property name="userName" value="${username1}"/> <property name="password" value="${pwd}"/> <!--<property name="name" value="${name1}"/>--> <property name="num" value="99999999"></property> </bean> <!--<bean id="bookDao" class="com.limei.dao.impl.BookDaoImpl"/>--> <bean id="userService" class="com.limei.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> <property name="num" value="1234"></property> </bean> </beans>5.data.properties资源username1=root123 pwd=1236.TestUser测试类通过spring获取资源（Service实例） import com.limei.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestUser { @Test public void save(){ ApplicationContext ctx = new ClassPathXmlApplicationContext ("applicationContext.xml"); // ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-user.xml","applicationContext-book.xml"); UserService userService = (UserService) ctx.getBean("userService"); userService.save(); } }
bean的属性介绍 集合类型数据注入 统一属性注入格式 properties文件 import的使用 ApplicationContext介绍 第三方资源配置 IoC配置（XML格式）基本属性：<bean id="beanId" name="别名1,别名2" class="ClassName"></bean>​ id：bean的名称，通过id值获取bean​ class：bean的类型​ name：bean的名称，可以通过name值获取bean，用于多人配合时给bean起别名格式：<bean scope="singleton"></bean>取值：singleton：设定创建出的对象保存在spring容器中，是一个单例的对象prototype：设定创建出的对象保存在spring容器中，是一个非单例的对象request、session、application、 websocket ：设定创建出的对象放置在web容器对应的位置格式：<bean init-method="init" destroy-method="destroy> </bean>取值：bean对应的类中对应的具体方法名注意事项：当scope=“singleton”时，spring容器中有且仅有一个对象，init方法在创建容器时仅执行一次当scope=“prototype”时，spring容器要创建同一类型的多个对象，init方法在每个对象创建时均执行一次当scope=“singleton”时，关闭容器会导致bean实例的销毁，调用destroy方法一次当scope=“prototype”时，对象的销毁由垃圾回收机制gc()控制，destroy方法将不会被执行基本属性：<property name="propertyName" value="propertyValue" ref="beanId" />​ name：对应bean中的属性名，要求该属性必须提供可访问的set方法（严格规范为此名称是set方法对应名称）​ value：设定非引用类型属性对应的值，不能与ref同时使用​ ref：设定引用类型属性对应bean的id ，不能与value同时使用注意：一个bean可以有多个property标签集合类型数据注入名称：array，list，set，map，props类型：标签归属：property标签 或 constructor-arg标签作用：注入集合数据类型属性格式：<property> </property>(1)集合类型数据注入——list<property name="al"> <value>limei</value> <value>66666</value> </property>(2)集合类型数据注入——props<property name="properties"> <props> <prop key="name">limei</prop> <prop key="value">666666</prop> </props> </property>(3)集合类型数据注入——array （了解）<property name="arr"> <array> <value>123456</value> <value>66666</value> </array> </property>(4)集合类型数据注入——set（了解）<property name="hs"> <set> <value>limei</value> <value>66666</value> </set> </property>(5)集合类型数据注入——map（了解）<property name="hm"> <entry key="name" value="limei"/> <entry key="value" value="6666666666"/> </property>统一属性注入格式Spring提供了对EL表达式的支持，统一属性注入格式类型：属性值归属：value属性值作用：为bean注入属性值格式：<bean><property value="EL"></bean>注意：所有属性值不区分是否引用类型，统一使用value赋值所有格式统一使用 value=“”常量 #{10} #{3.14} #{2e5} #{‘itcast’}引用bean #{beanId}引用bean属性 #{beanId.propertyName}引用bean方法 beanId.methodName().method2()引用静态方法 T(java.lang.Math).PI运算符支持 #{3 lt 4 == 4 ge 3}正则表达式支持 #{user.name matches‘[a-z]{6,}’}集合支持 #{likes[3]}案例：<bean id="userService" class="com.limei.service.impl.UserServiceImpl"> <property name="userDao" value="#{userDao}"/> <property name="bookDao" value="#{bookDao}"/> <property name="num" value="#{666666666}"/> <property name="version" value="#{'limei'}"/> </bean>properties文件Spring提供了读取外部properties文件的机制，使用读取到的数据为bean的属性赋值操作步骤1.准备外部properties文件2.开启context命名空间支持xmlns:context="http://www.springframework.org/schema/context"​3.加载指定的properties文件<context:property-placeholder location="classpath:filename.properties"/>​4.使用加载的数据<property name="propertyName" value="${propertiesName}"/>注意：如果需要加载所有的properties文件，可以使用*.properties表示加载所有的properties文件注意：读取数据使用${propertiesName}格式进行，其中propertiesName指properties文件中的属性名import的使用类型：标签归属：beans标签作用：在当前配置文件中导入其他配置文件中的项格式：<beans> <import /> </beans>基本属性：<import resource=“config.xml"/>​-resource：加载的配置文件名Spring容器加载多个配置文件new ClassPathXmlApplicationContext("config1.xml","config2.xml");Spring容器中的bean定义冲突问题同id的bean，后定义的覆盖先定义的导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同ApplicationContext介绍1.ApplicationContext是一个接口，提供了访问spring容器的API2.ClassPathXmlApplicationContext是一个类，实现了上述功能3.ApplicationContext的顶层接口是BeanFactory4.BeanFactory定义了bean相关的最基本操作5.ApplicationContext在BeanFactory基础上追加了若干新功能对比BeanFactory1.BeanFactory创建的bean采用延迟加载形式，使用才创建2.ApplicationContext创建的bean默认采用立即加载形式FileSystemXmlApplicationContext可以加载文件系统中任意位置的配置文件，而ClassPathXmlApplicationContext只能加载类路径下的配置文件BeanFactoryResource res = new ClassPathResource("applicationContext.xml"); BeanFactory bf = new XmlBeanFactory(res); UserService userService = (UserService)bf.getBean("userService");第三方资源配置阿里数据源方案Druid<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring_ioc"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean>
一对一查询 一对多查询 多对多查询 注解配置总结 需要的sql下载： 一对一 一对多 多对多 案例目录结构(一对一的)目录结构配置文件参考：Mybatis的基本使用注意：MyBatisConfig.xml配置文件里里替换成 <typeAliases> <!--<typeAlias type="com.limei.bean.Card" alias="card"/>--> <package name="com.itheima"/> </typeAliases>一对一查询一对一查询的需求：查询一个用户信息，与此同时查询出该用户对应的身份证信息Card实体类package com.limei.bean; public class Card { private Integer id; //主键id private String number; //身份证号 private Person p; //所属人的对象 public Card() { } public Card(Integer id, String number, Person p) { this.id = id; this.number = number; this.p = p; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public Person getP() { return p; } public void setP(Person p) { this.p = p; } @Override public String toString() { return "Card{" + "id=" + id + ", number='" + number + '\'' + ", p=" + p + '}'; } } Person实体类package com.limei.bean; public class Person { private Integer id; //主键id private String name; //人的姓名 private Integer age; //人的年龄 public Person() { } public Person(Integer id, String name, Integer age) { this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } } PersonMapper接口package com.limei.mapper; import com.limei.bean.Person; import org.apache.ibatis.annotations.Select; public interface PersonMapper { //根据id查询 @Select("SELECT * FROM person WHERE id=#{id}") public abstract Person selectById(Integer id); } CardMapper接口package com.limei.mapper; import com.limei.bean.Card; import com.limei.bean.Person; import org.apache.ibatis.annotations.One; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import java.util.List; public interface CardMapper { //查询全部 @Select("SELECT * FROM card") @Results({ @Result(column = "id",property = "id"), @Result(column = "number",property = "number"), @Result( property = "p", // 被包含对象的变量名 javaType = Person.class, // 被包含对象的实际数据类型 column = "pid", // 根据查询出的card表中的pid字段来查询person表 /* one、@One 一对一固定写法 select属性：指定调用哪个接口中的哪个方法 */ one = @One(select = "com.limei.mapper.PersonMapper.selectById") ) }) public abstract List<Card> selectAll(); } Test01测试类package com.limei.test; import com.limei.bean.Card; import com.limei.mapper.CardMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.InputStream; import java.util.List; public class Test01 { @Test public void selectAll() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.获取CardMapper接口的实现类对象 CardMapper mapper = sqlSession.getMapper(CardMapper.class); //5.调用实现类对象中的方法，接收结果 List<Card> list = mapper.selectAll(); //6.处理结果 for (Card card : list) { System.out.println(card); } //7.释放资源 sqlSession.close(); is.close(); } } 一对多查询一对多查询的需求：查询一个班级，与此同时查询出该班级对应的学生信息Classes实体类package com.limei.bean; import java.util.List; public class Classes { private Integer id; //主键id private String name; //班级名称 private List<Student> students; //班级中所有学生对象 public Classes() { } public Classes(Integer id, String name, List<Student> students) { this.id = id; this.name = name; this.students = students; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "Classes{" + "id=" + id + ", name='" + name + '\'' + ", students=" + students + '}'; } } Student实体类package com.limei.bean; import java.util.List; public class Student { private Integer id; //主键id private String name; //学生姓名 private Integer age; //学生年龄 public Student() { } public Student(Integer id, String name, Integer age) { this.id = id; this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } } StudentMapper接口package com.limei.mapper; import com.limei.bean.Student; import org.apache.ibatis.annotations.Select; import java.util.List; public interface StudentMapper { //根据cid查询student表 @Select("SELECT * FROM student WHERE cid=#{cid}") public abstract List<Student> selectByCid(Integer cid); }ClassesMapper接口package com.limei.mapper; import com.limei.bean.Classes; import org.apache.ibatis.annotations.Many; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import java.util.List; public interface ClassesMapper { //查询全部 @Select("SELECT * FROM classes") @Results({ @Result(column = "id",property = "id"), @Result(column = "name",property = "name"), @Result( property = "students", // 被包含对象的变量名 javaType = List.class, // 被包含对象的实际数据类型 column = "id", // 根据查询出的classes表的id字段来查询student表 /* many、@Many 一对多查询的固定写法 select属性：指定调用哪个接口中的哪个查询方法 */ many = @Many(select = "com.limei.mapper.StudentMapper.selectByCid") ) }) public abstract List<Classes> selectAll(); } Test01测试类package com.limei.test; import com.limei.bean.Classes; import com.limei.bean.Student; import com.limei.mapper.ClassesMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.InputStream; import java.util.List; public class Test01 { @Test public void selectAll() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.获取ClassesMapper接口的实现类对象 ClassesMapper mapper = sqlSession.getMapper( ClassesMapper.class); //5.调用实现类对象中的方法，接收结果 List<Classes> list = mapper.selectAll(); //6.处理结果 for (Classes cls : list) { System.out.println(cls.getId() + "," + cls.getName()); List<Student> students = cls.getStudents(); for (Student student : students) { System.out.println("\t" + student); } } //7.释放资源 sqlSession.close(); is.close(); } }多对多查询多对多查询的需求：查询学生以及所对应的课程信息Course实体类package com.limei.bean; public class Course { private Integer id; //主键id private String name; //课程名称 public Course() { } public Course(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Course{" + "id=" + id + ", name='" + name + '\'' + '}'; } } Student实体类package com.limei.bean; import java.util.List; public class Student { private Integer id; //主键id private String name; //学生姓名 private Integer age; //学生年龄 private List<Course> courses; //学生所选择的课程对象 public Student() { } public Student(Integer id, String name, Integer age, List<Course> courses) { this.id = id; this.name = name; this.age = age; this.courses = courses; } public List<Course> getCourses() { return courses; } public void setCourses(List<Course> courses) { this.courses = courses; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }CourseMapper接口package com.limei.mapper; import com.limei.bean.Course; import org.apache.ibatis.annotations.Select; import java.util.List; public interface CourseMapper { //根据学生id查询所选课程 @Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}") public abstract List<Course> selectBySid(Integer id); }StudentMapper接口package com.limei.mapper; import com.limei.bean.Student; import org.apache.ibatis.annotations.Many; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import java.util.List; public interface StudentMapper { //查询全部 @Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id") @Results({ @Result(column = "id",property = "id"), @Result(column = "name",property = "name"), @Result(column = "age",property = "age"), @Result( property = "courses", // 被包含对象的变量名 javaType = List.class, // 被包含对象的实际数据类型 column = "id", // 根据查询出student表的id来作为关联条件，去查询中间表和课程表 /* many、@Many 一对多查询的固定写法 select属性：指定调用哪个接口中的哪个查询方法 */ many = @Many(select = "com.limei.mapper.CourseMapper.selectBySid") ) }) public abstract List<Student> selectAll(); }Test01测试类package com.limei.test; import com.limei.bean.Course; import com.limei.bean.Student; import com.limei.mapper.StudentMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.InputStream; import java.util.List; public class Test01 { @Test public void selectAll() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper( StudentMapper.class); //5.调用实现类对象中的方法，接收结果 List<Student> list = mapper.selectAll(); //6.处理结果 for (Student student : list) { System.out.println(student.getId() + "," + student.getName() + "," + student.getAge()); List<Course> courses = student.getCourses(); for (Course cours : courses) { System.out.println("\t" + cours); } } //7.释放资源 sqlSession.close(); is.close(); } }配置总结@Results：封装映射关系的父注解。 Result[] value()：定义了 Result 数组 @Result：封装映射关系的子注解。 column 属性：查询出的表中字段名称 property 属性：实体对象中的属性名称 javaType 属性：被包含对象的数据类型 one 属性：一对一查询固定属性 @One：一对一查询的注解。 select 属性：指定调用某个接口中的方法 @Many：一对多查询的注解。 select 属性：指定调用某个接口中的方法