一,Spring整合MyBatis的步骤有哪些?
1. 导入 所需要的依赖
2.配置mybatis文件 mybatis-config mapper.xml
mybatis-config 不需要配置数据源 只需要取别名 引入映射文件
3.建立 domain mapper service 写一个查询所有的接口
4.建立spring配置文件
4.1 第一步 配置数据源
4.2 第二部 配置环境
4.3 第三步 整合mybatis SqlSessionFactory --》build -->sqlsession
MapperScannerConfigure
4.4 扫描包 service
5.写测试类
1 . applicationContext.xml 找不到 mybatis-config classpath多个*
2.mybatis 引入 映射文件 路径问题
3.userService 没有注入 扫描包 名字 对不对
4.com.jdbc.cj.mysql.driver 8.0 5 版本不要 cj
5.username和password 和 数据源重名 加 jdbc.username
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.配置数据源-->
<context:property-placeholder location="database.properties"></context:property-placeholder>
<!--2.配置环境 配置数据源-->
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置 SqlSessionFactoryBean-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!--配置 MapperScannerConfigurer-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"></property>
</bean>
<context:component-scan base-package="com.example.service"/>
</beans>
二,SqlSessionFactoryBean
底层执行以下步骤:
-
数据源配置:使用
setDataSource()
方法设置数据源,指定数据库连接信息。数据源可以是任何实现了javax.sql.DataSource接口的对象,如Apache Commons DBCP、C3P0或HikariCP等。 -
配置文件加载:使用
setConfigLocation()
方法设置MyBatis的配置文件的位置。配置文件通常是mybatis-config.xml,包含了全局的MyBatis配置信息,例如数据库连接池、事务管理器、类型别名等。SqlSessionFactoryBean会加载并解析该配置文件。 -
Mapper文件加载:使用
setMapperLocations()
方法设置Mapper接口对应的XML映射文件的位置。可以指定一个或多个Mapper文件,这些文件定义了SQL语句与Java方法的映射关系。SqlSessionFactoryBean会加载这些Mapper文件并与配置文件进行整合。 -
MyBatis配置:SqlSessionFactoryBean会根据配置文件和Mapper文件的定义生成一个org.apache.ibatis.session.Configuration对象。这个Configuration对象包含了MyBatis的所有配置信息,如类型别名、插件、拦截器等。
-
创建SqlSessionFactory:使用上述Configuration对象创建一个SqlSessionFactory实例。SqlSessionFactory是MyBatis的核心接口,负责创建SqlSession对象,它是与数据库交互的入口点。
-
额外配置:SqlSessionFactoryBean还提供了其他一些可选的配置方法,如
setTypeAliasesPackage()
设置类型别名的包路径,setPlugins()
设置插件等。这些配置方法可以根据需求进行调整。
最终,SqlSessionFactoryBean会在初始化过程中加载配置文件、Mapper文件,并根据配置信息创建一个SqlSessionFactory实例。这个SqlSessionFactory可以被SqlSessionDaoSupport或者MyBatis的SqlSessionUtils等类使用,用于创建和管理SqlSession实例,从而执行数据库操作。
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationContextAware {
private DataSource dataSource; // 数据源
private Resource configLocation; // MyBatis配置文件的位置
private String typeAliasesPackage; // 实体类的包路径
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // SqlSessionFactoryBuilder实例
private SqlSessionFactory sqlSessionFactory; // SqlSessionFactory实例
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void setConfigLocation(Resource configLocation) {
this.configLocation = configLocation;
}
public void setTypeAliasesPackage(String typeAliasesPackage) {
this.typeAliasesPackage = typeAliasesPackage;
}
@Override
public void afterPropertiesSet() throws Exception {
// 构建配置对象
Configuration configuration = sqlSessionFactoryBuilder.build(configLocation.getInputStream());
// 配置数据源
Environment environment = new Environment("default", new JdbcTransactionFactory(), dataSource);
configuration.setEnvironment(environment);
// 配置实体类别名
if (StringUtils.hasText(typeAliasesPackage)) {
TypeAliasRegistry typeAliasRegistry = configuration.getTypeAliasRegistry();
String[] packages = typeAliasesPackage.split(",");
for (String packageToScan : packages) {
typeAliasRegistry.registerAliases(packageToScan);
}
}
// 创建SqlSessionFactory实例
sqlSessionFactory = sqlSessionFactoryBuilder.build(configuration);
}
@Override
public SqlSessionFactory getObject() throws Exception {
return sqlSessionFactory;
}
@Override
public Class<?> getObjectType() {
return (this.sqlSessionFactory != null ? this.sqlSessionFactory.getClass() : SqlSessionFactory.class);
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// do nothing
}
}
三,MapperScannerConfigurer
MapperScannerConfigurer是一个后置处理器,用于自动扫描指定包路径下的Mapper接口,并将其注册为Spring的bean。它的底层实现如下:
-
实现接口:MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,该接口定义了在所有bean定义信息加载完成后、但在bean实例化之前触发的方法。这使得MapperScannerConfigurer能够在Spring容器加载bean定义时进行自定义的处理。
-
设置包路径:通过setBasePackage方法设置Mapper接口所在的包路径。可以使用通配符(如com.example.*.mapper)来指定多个包路径。
-
扫描Mapper接口:在postProcessBeanDefinitionRegistry方法中,MapperScannerConfigurer创建了一个ClassPathMapperScanner对象,并将指定的包路径传递给它。ClassPathMapperScanner是一个自定义的类,用于扫描指定包路径下的类文件。
-
注册Mapper接口:ClassPathMapperScanner会扫描指定包路径下的类,找到符合条件的类,例如标注了@Mapper注解的接口或符合命名规则的接口。然后,通过BeanDefinitionRegistry接口的registerBeanDefinition方法将这些类注册为Spring的bean。这些Mapper接口会以MapperFactoryBean的形式注册,MapperFactoryBean是一个特殊的Spring bean,用于创建Mapper接口的实例。
-
配置信息:MapperScannerConfigurer还提供了一些其他的配置选项,可以通过setAddToConfig方法设置是否将Mapper接口添加到MyBatis的配置中。如果设置为true,则会将这些Mapper接口添加到MyBatis的配置中,使得MyBatis能够自动管理这些Mapper接口的实例。
通过以上步骤,MapperScannerConfigurer能够自动扫描指定包路径下的Mapper接口,并将其注册为Spring的bean。这样,在需要使用Mapper接口的地方,可以直接通过@Autowired注解或其他方式进行依赖注入,从而方便地使用Mapper接口进行数据库操作。
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware {
private String basePackage; // Mapper接口所在的包路径
private boolean addToConfig = true; // 是否将Mapper接口添加到MyBatis的配置中
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 扫描指定包路径下的Mapper接口
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(addToConfig);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// do nothing
}
@Override
public void afterPropertiesSet() throws Exception {
// 检查basePackage是否已设置
Assert.notNull(basePackage, "Property 'basePackage' is required");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// do nothing
}
}
四,BasicDataSource
主要涉及以下几个关键点:
-
连接池初始化:在BasicDataSource的构造方法中,会初始化连接池的一些参数,如初始连接数(initialSize)、最大连接数(maxTotal)、最大空闲连接数(maxIdle)和最小空闲连接数(minIdle)。同时,还会创建指定数量的数据库连接,放入连接池中。
初始化连接池的过程中,会根据配置的驱动类名(driverClassName)、数据库连接URL(url)、用户名(username)和密码(password)创建数据库连接。具体的过程是通过JDBC驱动类加载数据库驱动,然后通过DriverManager获取数据库连接。
-
连接获取:当调用getConnection方法时,会先检查空闲连接池(idleConnections)是否为空。如果为空,就会根据连接池的大小和最大连接数来决定是否创建一个新的数据库连接。
如果连接池未满,则创建一个新的连接,添加到连接池中并返回。创建连接的过程与连接池初始化时类似,通过JDBC驱动类加载数据库驱动,然后通过DriverManager获取数据库连接。
如果连接池已满,则抛出SQLException异常,表示连接池已满,无法获取新的连接。
如果空闲连接池不为空,则从空闲连接池中获取一个连接,并检查连接是否关闭。如果连接关闭,则创建一个新的连接替代原来的连接。这样可以避免使用已关闭的连接,保证连接的可用性。
-
连接回收:在使用完数据库连接后,需要将连接返回给连接池进行复用。在BasicDataSource中,会将连接放回空闲连接池中,以供后续的连接获取操作使用。
-
连接状态检查:在获取连接时,会检查连接是否关闭。如果连接已关闭,则会创建一个新的连接替代原来的连接。这样可以避免使用已关闭的连接,保证连接的可用性。
-
连接的创建和销毁:在连接池中,会根据需要创建和销毁数据库连接。创建连接时,会使用JDBC驱动类加载数据库驱动,然后通过DriverManager获取数据库连接。销毁连接时,会调用Connection的close方法关闭连接。
在销毁连接之前,还会检查连接是否已关闭。如果连接未关闭,则调用Connection的close方法关闭连接。
连接的销毁是为了释放资源,避免资源的浪费。
BasicDataSource还提供了其他一些方法,如设置日志输出流、设置登录超时时间等,以便进行连接池的管理和配置。
总结来说,BasicDataSource底层实现主要通过维护连接池和使用连接池管理数据库连接的获取和释放,以提高数据库操作的性能和效率。它提供了简单而灵活的接口,方便开发人员使用和配置数据库连接池。
public class BasicDataSource implements DataSource, Serializable {
private String driverClassName; // JDBC驱动类名
private String url; // 数据库连接URL
private String username; // 数据库用户名
private String password; // 数据库密码
private int initialSize = 0; // 初始连接池大小
private int maxTotal = 8; // 最大连接数
private int maxIdle = 8; // 最大空闲连接数
private int minIdle = 0; // 最小空闲连接数
private List<Connection> connections = new ArrayList<>(); // 连接池中的连接
private List<Connection> idleConnections = new ArrayList<>(); // 空闲连接
// 设置驱动类名
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
// 设置数据库连接URL
public void setUrl(String url) {
this.url = url;
}
// 设置数据库用户名
public void setUsername(String username) {
this.username = username;
}
// 设置数据库密码
public void setPassword(String password) {
this.password = password;
}
// 设置初始连接池大小
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
// 设置最大连接数
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
// 设置最大空闲连接数
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
// 设置最小空闲连接数
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
// 获取数据库连接
@Override
public Connection getConnection() throws SQLException {
if (idleConnections.isEmpty()) {
if (connections.size() < maxTotal) {
Connection connection = createConnection();
connections.add(connection);
return connection;
} else {
throw new SQLException("Connection pool is full");
}
} else {
Connection connection = idleConnections.remove(0);
if (connection.isClosed()) {
connection = createConnection();
}
return connection;
}
}
// 获取数据库连接,带用户名和密码
@Override
public Connection getConnection(String username, String password) throws SQLException {
// 使用指定的用户名和密码获取连接
}
// 获取日志输出流
@Override
public PrintWriter getLogWriter() throws SQLException {
// 获取日志输出流
}
// 设置日志输出流
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// 设置日志输出流
}
// 设置登录超时时间
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// 设置登录超时时间
}
// 获取登录超时时间
@Override
public int getLoginTimeout() throws SQLException {
// 获取登录超时时间
}
// 将对象转换为指定的接口类型
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// 将对象转换为指定的接口类型
}
// 判断对象是否实现了指定的接口类型
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// 判断对象是否实现了指定的接口类型
}
// 创建数据库连接
private Connection createConnection() throws SQLException {
// 创建一个新的数据库连接
}
}