Прошло почти 3 года, как я начал обращаться к mybatis в колледже.Я думал о его использовании в последнее время, но я до сих пор не знаю деталей его внутренней реализации, таких как:
-
Как он загружает различные xml, связанные с mybatis?
-
Как он реализует операции с базой данных только через интерфейс Mapper + Mappe.xml (хотя многие могут знать, что он реализуется через прокси, но раз в глубинных интервью спрашивают: Например, как называется прокси-класс Mapper? Это реализовано через JDK или cglib??)?
-
В том же методе Mybatis несколько раз запрашивает базу данных. Вы хотите создать несколько сеансов SqlSession?
-
Как это подходит (интегрируется) с Spring?
-
Как гарантировать жизненный цикл SqlSession весной?
-
Дождитесь серии вопросов. . .
Если вы думаете, что не можете ответить на вышеуказанные вопросы, или если вы что-то знаете, то с этого момента давайте приоткроем завесу один за другим.
1. Mybatis: простейший тест Demo
Я считаю, что учащиеся, которые использовали Mybatis, не будут незнакомы с приведенным ниже кодом.Если вам что-то непонятно, вы можете прочитать егоОфициальная документация сайта
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 1、目前流行方式
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(101);
}
// 2、以前流行方式
try (SqlSession session = sqlSessionFactory.openSession()) {
User user = sqlSession.selectOne("xxx.UserMapper.selectById", "101");;
}
Код показывает процесс выполнения Mybatis операции с базой данных, который примерно разделен на (для текущего популярного метода фактически предыдущее использование совпадает с текущим популярным методом использования):
-
1. ПройтиSqlSessionFactoryBuilderСоздайте SqlSessionFactory из сборки ресурса чтения конфигурации.
-
2. ПройтиSqlSessionFactoryopenSession() получает доступ к SqlSession.
-
3. ПройтиSqlSessionПолучить прокси-объект Mapper (MapperProxy)
-
4. Операция запроса базы данных через маппер
SQLSession, SQLSessionFoatory, SQLSessionFactoryBuilder
Мы можем легко обнаружить, что каждый раз, когда мы запрашиваем операцию с базой данных, нам нужно передатьSqlSessionFactoryполучитьSqlSession, а SqlSessionFactory передаетсяSqlSessionFactoryBuilderСоздан, и SqlSession закрывается после завершения последней операции запроса. Так что не сложно придумать:
- SqlSessionFactoryЖелательно только 1 в приложении, т.е. один столбец.
- SqlSessionFactoryBuilderЕсть только один эффект: создать объект SqlSessionFactory.
- SqlSession должен существовать только в одном бизнес-запросе. Можно также сказать, что SqlSession соответствует сеансу базы данных. Он не является постоянным. Его необходимо создавать каждый раз при доступе к базе данных, а сеанс должен быть закрыт после доступа. завершено.
Что касается описания этих трех классов, а также объема и жизненного цикла картографа, я лично считаю, что официальная документация очень ясна:
SqlSessionFactoryBuilder
Этот класс можно создавать, использовать и отбрасывать, после создания SqlSessionFactory он больше не нужен. Таким образом, наилучшей областью для экземпляра SqlSessionFactoryBuilder является область действия метода (также известная как локальные переменные метода). Вы можете повторно использовать SqlSessionFactoryBuilder для создания нескольких экземпляров SqlSessionFactory, но лучше не оставлять его, чтобы можно было высвободить все ресурсы для синтаксического анализа XML для более важных задач.
SqlSessionFactory
Однажды созданный SqlSessionFactory должен существовать в течение всего времени выполнения приложения, нет причин отбрасывать его или воссоздавать другой экземпляр. Наилучшая практика использования SqlSessionFactory — не создавать его повторно несколько раз во время выполнения приложения, многократное перестроение SqlSessionFactory считается «неприятным запахом» кода. Таким образом, наилучшей областью действия для SqlSessionFactory является область приложения. Есть много способов сделать это, самый простой — использовать шаблон singleton или статический шаблон singleton.
SqlSession
Каждый поток должен иметь собственный экземпляр SqlSession. Экземпляры SqlSession не являются потокобезопасными и, следовательно, не могут использоваться совместно, поэтому их оптимальной областью действия является область запроса или метода. Вы никогда не должны помещать ссылку на экземпляр SqlSession в статическое поле класса, даже в переменную экземпляра класса. Также не следует помещать ссылку на экземпляр SqlSession в какую-либо управляемую область, такую как HttpSession в среде сервлетов. Если вы в настоящее время используете веб-платформу, рассмотрите возможность размещения SqlSession в области, аналогичной объекту HTTP-запроса. Другими словами, каждый раз, когда вы получаете HTTP-запрос, вы можете открыть SqlSession, вернуть ответ и закрыть его. Эта операция закрытия очень важна, вы должны поместить эту операцию закрытия в блок finally, чтобы гарантировать, что закрытие может выполняться каждый раз. Среды внедрения зависимостей могут создавать потокобезопасные, основанные на транзакциях SqlSessions и преобразователи и внедрять их непосредственно в ваши bean-компоненты, игнорируя, таким образом, их жизненный цикл. Если вас интересует, как использовать MyBatis через инфраструктуру внедрения зависимостей, вы можете изучить подпроекты MyBatis-Spring или MyBatis-Guice.
Экземпляр Mapper (экземпляр Mapper)Картографы — это создаваемые вами интерфейсы, которые связывают операторы, которые вы отображаете. Экземпляр интерфейса преобразователя получается из SqlSession. Таким образом, технически максимальная область действия любого экземпляра преобразователя такая же, как и у SqlSession, который их запросил. Тем не менее, наилучшей областью действия для экземпляра преобразователя является область действия метода. То есть экземпляры картографа должны запрашиваться в методе, который их вызывает, и отбрасываться после использования. Нет необходимости явно закрывать экземпляр преобразователя, хотя нет ничего плохого в сохранении экземпляра преобразователя во всей области запроса, но вы быстро обнаружите, что, как и в случае с SqlSession, управление слишком большим количеством ресурсов в этой области будет трудно контролировать. Чтобы избежать этой сложности, лучше всего поместить преобразователь в область действия метода. Так же, как показанный код. Если внедряется SqlSession, экземпляр преобразователя также можно внедрить посредством внедрения зависимостей, и его время жизни можно игнорировать.
2. Mybatis-Spring: бесшовная интеграция кода MyBatis в Spring.
Фронт — это код, который часто можно увидеть при изучении mybatis, но и недостатки очевидны: SqlSession должен создаваться для каждого запроса, а прокси-класс Mapper получается через SqlSession (свидетельствуя о том, что связанность очень высокая), а значит что каждый запрос Все должны создать новый класс прокси Mapper. Чтобы интегрировать Spring и решить предыдущие проблемы, поэтомуMybatis-SpringПодпроекты идут.
MyBatis-Spring поможет вам легко интегрировать код MyBatis в Spring.Это позволит MyBatis участвовать в управлении транзакциями Spring, создавать Mapper Mapper и SqlSession и внедрять в bean-компоненты..
Вышеизложенное является официальным введением Mybatis-Spring, котороеРазрешить MyBatis участвовать в управлении транзакциями Spring, создавать Mappers Mapper и SqlSession и внедрять в bean-компонентыЭто ключевой момент нашего анализа. Тогда приступайте к анализу!
SqlSessionFactoryBean , MapperScannerConfigurer
Когда Mybatis применяется в проекте Spring, будут следующие две конфигурации компонентов: эти две конфигурации являются начальными конфигурациями для загрузки xml, сопоставления и внедрения SqlSession.
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="xxx.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
1. SqlSessionFactoryBean: загрузите xml и создайте объект SqlSessionFactory.
SqlSessionFactoryBean, который мы видим из конфигурации, настраивает источник данных, путь xml для сопоставления и путь xml для mybatis-config. Поэтому нетрудно представить, что SqlSessionFactoryBean реализует загрузку файлов конфигурации xml и создание объектов SqlSessionFactory. Давайте посмотрим на граф наследования SqlSessionFactoryBean:
В диаграмме отношений наследования мы находимИнициализацияBean, FactoryBeanНа рисунке студенты, которые могут это знать, вероятно, догадались, что должны быть afterPropertiesSet() для создания объектов SqlSessionFactory и getObject() для получения объектов SqlSessionFactory. Без лишних слов давайте взглянем на реализацию getObject():
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
getObject() относительно прост.Все мы знаем, что подклассы FactoryBean получают фактический объект Bean через getObject(), который здесь SqlSessionFactory. Из исходного кода видно, что afterPropertiesSet() будет вызываться, когда sqlSessionFactory имеет значение null, поэтому SqlSessionFactory должен быть создан с помощью afterPropertiesSet(). Продолжайте смотреть на реализацию afterPropertiesSet():
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
this.sqlSessionFactory = buildSqlSessionFactory();
}
afterPropertiesSet() сначала проверяет, что dataSource и sqlSessionFactoryBuilder имеют значение null, и, наконец, вызывает метод buildSqlSessionFactory() для получения объекта SqlSessionFactory и присваивает его свойству поля класса sqlSessionFactory . Продолжайте просматривать исходный код buildSqlSessionFactory():
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
// 省略了 SqlSessionFactoryBean 的属性(比如:ObjectFactory )赋值到 Configuration 对象中的操作
// 1 Configuration : Mybatis的核心类之一,主要存放读取到的xml数据,包括mapper.xml
Configuration configuration;
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configLocation != null) {
// 2 创建 xmlConfigBuilder 对象 : 用于解析 mybatis-config.xml 数据
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
} else {
if (logger.isDebugEnabled()) {
logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
}
configuration = new Configuration();
configuration.setVariables(this.configurationProperties);
}
if (xmlConfigBuilder != null) {
try {
// 3 XmlConfigBuilder 解析方法执行
xmlConfigBuilder.parse();
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}
if (!isEmpty(this.mapperLocations)) {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
// 4 创建 XMLMapperBuilder 对象 : 用于解析 mapper.xml 数据
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
}
}
// 5 通过 SqlSessionFactoryBuilder bulid SqlSessionFactory 对象
return this.sqlSessionFactoryBuilder.build(configuration);
}
Весь исходный код buildSqlSessionFactory() в основном имеет следующие важные моменты:
-
1,XMLConfigBuilder, проанализируйте конфигурацию mybatis-config.xml, вызвав его метод parse() (если mapper.xml сконфигурирован, он будет проанализирован и загружен через XMLMapperBuilder), и назначьте проанализированные данные вConfiguration(Один из основных классов Mybatis, который в основном хранит прочитанные данные xml, включая mapper.xml, который проходит через весь mybatis, достаточно, чтобы увидеть его важность)
-
2,XMLMapperBuilder: проанализируйте конфигурацию mapper.xml, вызвав его метод parse(), и назначьте проанализированные данныеConfiguration
-
3. Сохранит проанализированные данныеConfigurationтак какsqlSessionFactoryBuilderпараметры .build(), создатьsqlSessionFactoryобъект.
слишком далеко
2. MapperScannerConfigurer: просканируйте путь к интерфейсу Mapper и замените луч кражи Mapper на MapperFactoryBean.
MapperScannerConfigurer находится в проекте mybatis-spring, чтобы облегчить загрузку интерфейса Mapper и заменить луч Mapper столбцомMapperFactoryBean. Просмотрите исходный код MapperScannerConfigurer, сначала посмотрите на его схему наследования:
От которого мы наследуем интерфейс BeanDefinitionRegistryPostProcessor, студенты, знакомые со Spring, должны были примерно подумать, как заменить Mapper на новый.MapperFactoryBean. Без лишних слов давайте посмотрим, как MapperScannerConfigurer реализует метод postProcessBeanDefinitionRegistry BeanDefinitionRegistryPostProcessor:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
Мы можем обнаружить, что весь метод фактически проходит черезClassPathMapperScannerМетод scan() из , посмотрите на реализацию scan() и обнаружите, что ключевой метод doScan() вызывается внутри, затем давайте взглянем на реализацию метода doScan():
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 1、调用父类 ClassPathBeanDefinitionScanner的 doScan方法 加载路径下所有的mapper接口生成对应的 BeanDefinition
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
// 2、 设置 被代理的 Bean(也就是Mapper) 的class信息
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
// 3、 偷梁换柱成 MapperFactoryBean
definition.setBeanClass(MapperFactoryBean.class);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
// 4、 设置 sqlSessionFactory
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
// 5、 设置 sqlSessionTemplate
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
return beanDefinitions;
}
Весь метод делится на 3 части:
-
1. Вызовите метод doScan() родительского класса ClassPathBeanDefinitionScanner, чтобы загрузить все интерфейсы сопоставления по пути для создания соответствующего BeanDefinition.
-
2. Через определение.setBeanClass(MapperFactoryBean.class) украсть луч и заменить его на MapperFactoryBean
-
3. Добавьте информацию о параметрах поля или метода, требуемую MapperFactoryBean, с помощью определения.getPropertyValues().add(): sqlSessionFactory, mapperInterface и т. д.
На этом миссия MapperScannerConfigurer завершена, и создание MapperFactoryBean полностью отдано на откуп Spring.
3. MapperFactoryBean, SqlSessionTemplate: инструмент для разделения Mapper и SqlSession
Мы знаем, что в mybatis Mapper создается через SqlSession, а жизненный цикл SqlSession только в одной сессии, поэтому по этой схеме SqlSession должен создаваться для каждой сессии, а затем Mapper создается через SqlSession. Мы знаем, что Mapper на самом деле не нужно создавать каждый раз, он больше подходит как одностолбцовый объект. Так как же разделить SqlSession и Mapper? Он реализован в проекте mybatis-spring через MapperFactoryBean и SqlSessionTemplate. Далее мы их разберем.
MapperFactoryBean
Как мы видели ранее, MapperFactoryBean на самом деле можно понимать как прокси-объект фабрики Mapper.Мы можем получить прокси-объект Mapper через метод MapperFactoryBean. Давайте посмотрим на отношение наследования MapperFactoryBean:
Мы видим, что MapperFactoryBean реализует FactoryBean, поэтому прокси-объект Mapper должен быть получен путем реализации getObject(). Проверьте исходный код следующим образом:
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
Внутри находится знакомый метод getSqlSession().getMapper() для создания прокси-объекта Mapper. Студенты, знакомые со Spring, знают, что в процессе загрузки bean-компонента, если текущий объект bean-компонента окажется FactoryBean, он вызовет getObject() для получения реального объекта bean-компонента. Незнакомые студенты могут взглянуть на метод getBean() класса AbstractBeanFactory.
Но, кажется, нет никаких признаков разделения SqlSession и Mapper? Не волнуйтесь, давайте продолжим изучение getSqlSession() и обнаружим, что это реализация родительского класса SqlSessionDaoSupport. Давайте посмотрим на исходный код SqlSessionDaoSupport:
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
// 创建 SqlSession子类 SqlSessionTemplate
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
public SqlSession getSqlSession() {
return this.sqlSession;
}
....
}
Мы обнаружили, что полученный SqlSession на самом деле является его подклассомSqlSessionTemplate, смотрим исходный код его метода построения:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
// 维护了一个 SqlSession的代理对象
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
Мы ясно видим, что он поддерживает внутреннее поле sqlSessionProxy SqlSession, которое назначает прокси-объект SqlSessionInterceptor. Давайте еще раз посмотрим на исходный код SqlSessionInterceptor:
private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 通过getSqlSession() 获取一个 SqlSession
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
Когда мы найдем его реализацию прокси, получим новый SqlSession через getSqlSession(). Другими словами, SqlSession, который создает Mapper, и SqlSession, который запрашивает сеанс, не совпадают. Здесь Mapper и SqlSession полностью отделены друг от друга, а объем жизненного цикла каждого сеанса SqlSession гарантирован.
Это выходит за рамки предпосылки: getSqlSession().getMapper() на самом деле получается через configuration.getMapper(), а это означает, что информация Mapper должна быть добавлена в конфигурацию, так когда же добавляется конфигурация? Вы можете посмотреть на метод checkDaoConfig() MapperFactoryBean, Исходный код выглядит следующим образом:
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Throwable t) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
throw new IllegalArgumentException(t);
} finally {
ErrorContext.instance().reset();
}
}
}
Поскольку родительский класс реализует интерфейс InitializingBean, а его afterPropertiesSet() вызывает метод checkDaoConfig(), по крайней мере, при первоначальном создании MapperFactoryBean информация Mapper должна быть добавлена в конфигурацию.
3. Личное резюме
В этой статье анализируется интеграция Mybatis и Spring.Ключевые объекты включают в себя:
-
SqlSessionFactoryBuilder: используется для создания SqlSessionFactory
-
SqlSessionFactory: используется для создания SqlSession
-
SqlSession: интерфейс сеанса API верхнего уровня для работы Mybatis, все операции по доступу к базе данных выполняются через SqlSession.
-
Configuration: Хранит всю информацию о конфигурации mybatis, включая mapper.xml, mybatis-config.xml и т. д.
-
XMLConfigBuilder: Разберите конфигурацию mybatis-config.xml и сохраните ее в Configuration
-
XMLMapperBuilder: Разобрать конфигурацию mapper.xml и сохранить ее в Configuration
-
SqlSessionFactoryBean: FactoryBean, который генерирует SqlSessionFactory, когда mybatis интегрирует Spring
-
MapperScannerConfigurer: Когда mybatis интегрирует Spring, удобно загрузить интерфейс Mapper и заменить Mapper столбцом.MapperFactoryBean
-
MapperFactoryBean: FactoryBean, который генерирует прокси-объекты Mapper.
-
SqlSessionTemplate: Внутренне поддерживает прокси-объект SqlSession и отделяет ключевые объекты Mapper и SqlSession.
Если вы заинтересованы в них, добро пожаловать, пометьте, подпишитесь, добавьте в избранное и вперед, чтобы поддержать!
Эта статья опубликована в блогеOpenWriteвыпускать!