MyBatis 是一种基于 Java 的 ORM(对象关系映射)框架,它并没有明确地使用大量的设计模式,而是借鉴了一些设计模式的思想和实践。以下是 MyBatis 中涉及的一些设计模式:
数据访问对象模式(DAO):
MyBatis 中使用了 DAO 模式来将数据库操作从业务逻辑中分离出来。通过 DAO 接口和相应的实现类,将数据库操作进行封装和管理。下面是一个 MyBatis 数据访问对象(DAO)模式的代码示例:\
DAO代码示例
假设有一个 User 实体类,其属性包括 id、name 和 age。在 MyBatis 中,我们需要创建一个对应的 UserMapper 接口和 UserMapper.xml 文件来实现与数据库的交互。
- User 实体类
public class User {
private int id;
private String name;
private int age;
// 省略 getter 和 setter 方法
}
- UserMapper 接口
public interface UserMapper {
/**
* 根据用户 ID 查询用户信息
* @param id 用户 ID
* @return User 用户信息
*/
User getUserById(int id);
/**
* 添加用户信息
* @param user 用户信息
*/
void addUser(User user);
/**
* 更新用户信息
* @param user 用户信息
*/
void updateUser(User user);
/**
* 删除用户信息
* @param id 用户 ID
*/
void deleteUser(int id);
}
- UserMapper.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 根据用户 ID 查询用户信息 -->
<select id="getUserById" parameterType="int" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 添加用户信息 -->
<insert id="addUser" parameterType="com.example.entity.User">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
<!-- 更新用户信息 -->
<update id="updateUser" parameterType="com.example.entity.User">
UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
</update>
<!-- 删除用户信息 -->
<delete id="deleteUser" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>
在这个示例中,我们定义了一个 UserMapper 接口和一个 UserMapper.xml 文件。在 UserMapper 接口中,我们定义了一些方法,这些方法对应着数据库中的操作,比如查询用户信息、添加用户信息、更新用户信息和删除用户信息等。在 UserMapper.xml 文件中,我们定义了每个方法对应的 SQL 语句,MyBatis 将根据这些 SQL 语句来执行数据库操作。
使用 MyBatis 的时候,我们只需要注入 UserMapper 接口的实现类即可,然后就可以通过调用 UserMapper 接口中的方法来实现对数据库的操作了。例如:
@Autowired
private UserMapper userMapper;
// 根据用户 ID 查询用户信息
User user = userMapper.getUserById(1);
// 添加用户信息
User newUser = new User();
newUser.setName("xiaobei");
newUser.setAge(23);
userMapper.addUser(newUser);
建造者模式(Builder)
MyBatis 中的配置文件可以使用建造者模式进行构建。例如,通过 XMLConfigBuilder 来构建 SqlSessionFactory 实例。
MyBatis 的配置文件(XML 文件)使用了 Builder 模式具体过程
在 MyBatis 中,XML 配置文件用于定义 SQL 映射以及其他的配置信息。
MyBatis 的配置文件使用了 Builder 模式来创建和配置 SqlSessionFactory 对象。具体的过程如下:
- 创建一个 Configuration 对象:在 MyBatis 中,所有的配置信息都存储在 Configuration 对象中,因此我们需要首先创建一个 Configuration 对象。
- 配置数据源:在 Configuration 对象中配置数据源的相关信息,包括数据库驱动、连接池、连接字符串等。
- 配置类型别名:在 Configuration 对象中配置 Java 类型和 SQL 类型之间的别名映射,以便在 XML 配置文件中使用 Java 类型来代替 SQL 类型。
- 配置映射器:在 Configuration 对象中配置映射器,即将 Java 对象和 SQL 语句进行映射的配置信息。映射器可以通过 XML 文件或注解的方式来配置。
- 使用 SqlSessionFactoryBuilder 构建 SqlSessionFactory:使用 SqlSessionFactoryBuilder 对象来创建 SqlSessionFactory 对象,同时将 Configuration 对象传递给 SqlSessionFactoryBuilder 对象。
- 使用 SqlSessionFactory 获取 SqlSession:通过 SqlSessionFactory 对象来获取 SqlSession 对象,SqlSession 对象用于执行 SQL 语句。
XMLConfigBuilder 来构建 SqlSessionFactory 实例具体过程
MyBatis中的SqlSessionFactory是用于创建SqlSession实例的工厂类。要创建SqlSessionFactory实例,需要使用XML配置文件或Java代码进行配置。下面是使用XML配置文件进行配置的具体过程:
- 创建一个XML配置文件。例如,文件名为"mybatis-config.xml"。该文件可以包含以下内容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
<property name="username" value="myuser"/>
<property name="password" value="mypassword"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
上面的配置文件定义了一个环境(development)和一个数据源(POOLED),以及一个Mapper映射文件。其中,数据源配置中的"driver"、“url”、“username”、"password"属性需要根据实际情况进行修改。
- 创建一个XMLConfigBuilder实例。该实例将解析XML配置文件并构建Configuration对象。例如:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
XMLConfigBuilder configBuilder = new XMLConfigBuilder(inputStream);
Configuration configuration = configBuilder.parse();
- 通过Configuration对象构建SqlSessionFactory实例。例如:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);
上述代码中,SqlSessionFactoryBuilder()用于创建SqlSessionFactory实例。它需要一个Configuration对象作为参数。Configuration对象包含了MyBatis的所有配置信息,包括数据源配置、类型别名、插件等。
通过以上步骤,就可以创建一个SqlSessionFactory实例,然后使用它来创建SqlSession实例,从而进行数据库操作。例如:
SqlSession session = sessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
System.out.println(user);
} finally {
session.close();
}
上述代码中,我们首先通过SqlSessionFactory创建了一个SqlSession实例。然后,使用SqlSession实例获取了一个UserMapper的代理对象,并使用它来查询数据库中的一个用户。最后,记得关闭SqlSession实例。
工厂模式(Factory)
MyBatis 中使用了工厂模式来创建 SqlSession、SqlSessionFactory、SqlSessionFactoryBuilder 等实例。例如,通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例,通过 SqlSessionFactory 创建 SqlSession 实例。
SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例
SqlSessionFactoryBuilder 是 MyBatis 中用于创建 SqlSessionFactory 实例的类。它通过解析 MyBatis 配置文件(mybatis-config.xml)以及 Mapper 映射文件(*.xml)来创建 SqlSessionFactory 实例。具体过程如下:
- 首先,SqlSessionFactoryBuilder 会读取 MyBatis 配置文件 mybatis-config.xml,并将其解析为一个 org.apache.ibatis.session.Configuration 对象。
- 接着,SqlSessionFactoryBuilder 会读取 Mapper 映射文件(*.xml),并将其解析为一个 org.apache.ibatis.mapping.MappedStatement 对象。MappedStatement 对象中包含了 SQL 语句、参数映射信息、结果集映射信息等。
- SqlSessionFactoryBuilder 会将 Configuration 对象中的 MappedStatement 对象和其他属性设置(比如数据库连接池、插件等)与 Mapper 映射文件中的 MappedStatement 对象合并,最终创建一个 SqlSessionFactory 实例。
- SqlSessionFactoryBuilder 最后返回 SqlSessionFactory 实例,开发者可以使用该实例创建 SqlSession 对象并执行 SQL 操作。
SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例的过程是读取配置文件、解析配置文件、合并配置信息,并最终创建 SqlSessionFactory 实例的过程。
通过 SqlSessionFactory 创建 SqlSession 实例
SqlSession 是 MyBatis 中用于与数据库交互的核心类,通过 SqlSessionFactory 创建 SqlSession 实例的过程如下:
- 首先,开发者需要通过 SqlSessionFactoryBuilder 创建一个 SqlSessionFactory 实例,该实例包含了 MyBatis 的配置信息以及数据库连接信息。
- 接着,开发者可以通过 SqlSessionFactory 的 openSession() 方法创建一个 SqlSession 实例。openSession() 方法提供了多个重载形式,可以设置事务级别、是否自动提交事务、执行器类型等。
- SqlSessionFactory 会通过创建一个 org.apache.ibatis.session.defaults.DefaultSqlSession 实例来实现 SqlSession 接口,同时将 SqlSession 的配置信息、数据源、事务管理器等信息传递给 DefaultSqlSession。
- 在 SqlSession 中,开发者可以通过调用 select、insert、update、delete 等方法执行 SQL 操作,同时 SqlSession 会将 SQL 语句、参数、结果集映射等信息交给 Executor 对象进行执行。
- SqlSession 执行 SQL 操作完成后,会将结果返回给开发者,同时释放数据库连接。
通过 SqlSessionFactory 创建 SqlSession 实例的过程就是创建 SqlSession 对象,并将其与配置信息、数据库连接等相关信息绑定在一起。开发者可以通过 SqlSession 对象来执行 SQL 操作,并最终释放数据库连接。
适配器模式(Adapter)
MyBatis 中使用了适配器模式来将各种不同的数据源适配成统一的接口。例如,通过 DataSourceFactory 来创建 DataSource 实例,从而适配各种不同的数据源。
通过 DataSourceFactory 来创建 DataSource 实例
DataSourceFactory 是 MyBatis 中用于创建 DataSource 实例的工厂类,通过它可以创建不同类型的数据源,如 C3P0、Druid、HikariCP 等。创建 DataSource 实例的具体过程如下:
- 首先,开发者需要在 MyBatis 的配置文件(mybatis-config.xml)中配置数据源相关的信息,如数据源类型、驱动、URL、用户名、密码等。
- 接着,在配置文件中配置 DataSourceFactory 的类型和属性,如下所示:
<dataSource type="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
上述代码中,type 属性指定了数据源类型为 DruidDataSource,property 元素指定了该数据源的属性,如驱动、URL、用户名、密码等。
- 当 SqlSessionFactoryBuilder 解析配置文件时,会通过 DataSourceFactory 创建 DataSource 实例。首先,它会根据 type 属性的值创建一个 DataSourceFactory 实例。然后,它会调用 DataSourceFactory 的 setProperties() 方法,并将配置文件中的属性设置传递给该方法。DataSourceFactory 实例将根据属性值来创建对应类型的数据源实例。
- 最后,SqlSessionFactoryBuilder 将数据源实例设置到 Configuration 对象中,以便后续使用。
通过 DataSourceFactory 创建 DataSource 实例的过程就是读取配置文件中的数据源相关信息、创建 DataSourceFactory 实例、设置属性并创建数据源实例,最终将数据源实例设置到 Configuration 对象中。
动态代理模式(Dynamic Proxy)
MyBatis 中使用了动态代理模式来创建 DAO 接口的实现类。例如,通过 MapperProxyFactory 来创建 MapperProxy 实例,从而代理 DAO 接口的方法调用。
参考:https://blog.csdn.net/Fornewknowledge/article/details/129740798
模板方法模式(Template Method)
MyBatis 中的 SqlSessionTemplate 类使用了模板方法模式来封装和管理数据库操作。例如,通过模板方法 selectOne、selectList 等来执行不同的 SQL 语句。下面是MyBatis中使用模板方法模式进行数据访问的具体过程
- 定义抽象模板类
在MyBatis中,定义了一个抽象类BaseExecutor,该类作为执行器的抽象模板,其中包含了一些公共的方法,例如update、query等,以及模板方法doUpdate、doQuery等,具体实现留给子类来完成。
- 定义具体子类
MyBatis中有多种不同的执行器,例如SimpleExecutor、ReuseExecutor等,它们都是BaseExecutor的具体子类,负责实现BaseExecutor中的抽象方法。
- 实现具体方法
在子类中,实现BaseExecutor中的doUpdate、doQuery等模板方法,完成具体的数据访问操作。例如,在SimpleExecutor中,doUpdate方法会创建一个Statement对象,执行SQL语句,然后返回影响的行数。
- 调用模板方法
在应用程序中,通过调用BaseExecutor中的公共方法来执行数据访问操作。这些方法会调用对应的模板方法,然后由子类来实现具体的数据访问操作。例如,调用update方法时,会执行doUpdate方法完成更新操作。
MyBatis使用模板方法模式来实现数据访问操作,将公共的方法放在抽象模板类中,由子类来实现具体的操作,避免了重复代码的产生,提高了代码的可复用性和可维护性。
装饰器模式(Decorator)
MyBatis 中的 SqlSession 对象可以使用装饰器模式来对其进行功能扩展。下面是MyBatis中使用装饰器模式进行功能扩展的具体过程
- 定义抽象组件
在MyBatis中,定义了一个抽象接口StatementHandler,该接口定义了一些基本的方法,例如prepare、parameterize等,用于执行SQL语句的操作。
- 定义具体组件
MyBatis中包含多种不同的StatementHandler实现,例如RoutingStatementHandler、PreparedStatementHandler等,它们都是StatementHandler接口的具体实现,负责实现StatementHandler中定义的方法。
- 定义抽象装饰器
为了能够对StatementHandler进行扩展,需要定义一个抽象装饰器类BaseStatementHandler,该类也实现了StatementHandler接口,并且持有了一个StatementHandler对象的引用,用于将装饰器的操作传递给被装饰对象。
- 定义具体装饰器
MyBatis中有多种具体装饰器,例如StatementHandlerInterceptor、ParameterHandlerInterceptor等,它们都是BaseStatementHandler的具体子类,负责实现BaseStatementHandler中定义的方法,并在其中调用被装饰对象的相应方法,完成对StatementHandler的扩展和定制。
- 应用装饰器
在MyBatis中,可以通过配置文件或代码方式来应用装饰器,例如可以在配置文件中通过plugins标签来配置具体的装饰器,或者通过InterceptorChain来添加装饰器。
MyBatis使用装饰器模式来实现功能的扩展和定制,通过对抽象组件和具体组件的定义,以及抽象装饰器和具体装饰器的实现,实现了对StatementHandler等核心组件的扩展和定制,提高了框架的灵活性和可扩展性。
通过 TransactionalSqlSessionDecorator 来实现事务的支持
为了支持事务,MyBatis提供了一个名为TransactionalSqlSessionDecorator的装饰器,它可以将SqlSession对象包装成一个支持事务的对象。以下是一个简单的示例代码,演示如何使用TransactionalSqlSessionDecorator来实现事务支持
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class MyBatisService {
private final SqlSessionTemplate sqlSessionTemplate;
public MyBatisService(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
public void insertUser(User user) {
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(TransactionIsolationLevel.READ_COMMITTED);
try {
session.insert("insertUser", user);
session.commit();
} catch (Exception e) {
session.rollback();
throw e;
} finally {
session.close();
}
}
public void updateUser(User user) {
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(TransactionIsolationLevel.READ_COMMITTED);
try {
session.update("updateUser", user);
session.commit();
} catch (Exception e) {
session.rollback();
throw e;
} finally {
session.close();
}
}
public void deleteUser(int userId) {
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(TransactionIsolationLevel.READ_COMMITTED);
try {
session.delete("deleteUser", userId);
session.commit();
} catch (Exception e) {
session.rollback();
throw e;
} finally {
session.close();
}
}
}
在上述代码中,我们通过注解@Transactional来表示该类中的方法都需要进行事务管理。接着,我们在每个方法中使用TransactionalSqlSessionDecorator类来获取SqlSession对象,并且设置了事务的隔离级别为READ_COMMITTED。之后,我们在try-catch-finally代码块中实现了事务的提交和回滚操作。
注意,在MyBatis中,我们可以使用多种方式来管理事务,例如通过Spring框架提供的@Transactional注解来实现事务的声明式管理,也可以通过使用SqlSessionTemplate类的事务控制来实现编程式管理。在这个例子中,我们采用了编程式管理事务的方式。
总结
MyBatis 并没有过多地依赖于设计模式,而是根据具体的需求和场景灵活地运用不同的设计模式来解决问题。