В настоящее время крупномасштабные системы электронной коммерции в основном используют технологию разделения чтения и записи на уровне базы данных, которая представляет собой основную базу данных и несколько рабов. Мастерская библиотека отвечает за обновления данных и запрос данных в реальном времени, а библиотека рабов отвечает за запрос данных без реального времени. Поскольку в реальных приложениях базы данных читают больше и записывают меньше (частота данных чтения высока, а частота обновления данных относительно невелика), а данные чтения обычно длиннее и занимают больше процессоров на сервере базы данных, что влияет на пользовательский опыт. Наш обычный подход состоит в том, чтобы извлечь запрос из основной библиотеки, использовать несколько рабовладельческих библиотек и использовать балансировку нагрузки, чтобы снизить давление запроса каждой рабовладельческой библиотеки.
Цель использования технологии разделения чтения и записи состоит в том, чтобы эффективно снизить давление на главную библиотеку и распространять запросы на данные пользователя в различные рабские библиотеки, что обеспечивает тем самым надежность системы. Давайте посмотрим на фон использования разделения чтения-записи.
Поскольку бизнес веб -сайта продолжает расширяться, данные продолжают расти, а больше пользователей давление на базу данных становится все больше и больше. Традиционные методы, такие как: база данных или оптимизация SQL в основном не могут соответствовать требованиям. В настоящее время стратегия разделения чтения и письма может использоваться для изменения статус -кво.
В частности, в разработке, как легко достичь разделения чтения и записи? Существует два широко используемых метода:
1 Первый метод является наиболее часто используемым методом, который заключается в определении двух соединений базы данных, одним из них является MasterDataSource, а другой - Slavedatasource. При обновлении данных мы читаем MasterDataSource и при запросе данных мы читаем Slavedatasource. Этот метод очень прост, поэтому я не буду вдаваться в подробности.
2 Второй метод динамического переключения источника данных состоит в том, чтобы динамически вплетать источник данных в программу при запуске программы, чтобы выбрать прочитать главную библиотеку или библиотеку рабов. Основные технологии используются: аннотация, пружина AOP, отражение. Метод реализации будет подробно описан ниже.
Перед введением метода реализации мы подготовим некоторые необходимые знания, класс Spring AbstractingingDataSource
AbstractroutingDatasource Class был добавлен после весны 2.0. Давайте сначала рассмотрим определение AbstractroutingDatasource:
Кода -копия выглядит следующим образом:
Общественный абстрактный класс AbstractroutingDatasource расширяет AbstractDatasource реализует инициализацию Bean {}
AbstractroutingDatasource наследует AbstractDatasource, который является подклассом данных. DataSource - это интерфейс источника данных javax.sql, определяемый следующим образом:
DataSource Public Interface Extends CommondatAsource, warpper { /** * <p> Попытки установить соединение с источником данных, которое представляет объект DataSource < /code>. * * @return Подключение к источнику данных * @exception sqlexception Если возникает ошибка доступа к базе данных */ connection getConnection () Throws Sqlexception; /** * <p> Попытки установить соединение с источником данных, что представляет объект DataSource </code> DataSource </code>. * * @param Имя пользователя базы данных Пользователь базы данных, на стороне которой подключение * создается * @param Пароль Пароль пользователя * @return Подключение к источнику данных * @exception sqlexception, если возникает ошибка доступа к базе данных * @since 1.4 */ connection getConnection (String Searname, String Password) Throws Sqlexception;}; Интерфейс DataSource определяет два метода, оба из которых являются подключениями к базе данных. Давайте посмотрим, как AbstractroutingDataSource реализует интерфейс данных:
public Connection getConnection () Throws SQLexception {return DetrinetArgetDataSource (). getConnection (); } public Connection getConnection (String username, String Password) Throws SQLexception {return DetrinetArgetDatasource (). getConnection (username, пароль); } Очевидно, что это позвонить своему собственному методу DetrinetArgetDataSource (), чтобы получить соединение. Метод DiteMetArgetDataSource определяется следующим образом:
Защищенный данных DETRINETARGETDATASOURCE () {assert.notnull (this.ResolvedDataSources, «маршрутизатор данных не инициализирован»); Object Lookupkeke = DetrineCurrentLookupKey (); DataSource DataSource = this.ResolvedDataSources.get (LookupKey); if (dataSource == null && (this.lenientFallback || lookupkey == null)) {dataSource = this.ResolvedDefaultDataSource; } if (dataSource == null) {throw new allogalStateException («Не может определить целевой дат данных для ключа поиска [" + lookupkey + "]"); } return DataSource; }Мы заботимся о следующих двух предложениях:
Object LookupKey = degineCurrentLookupKey (); DataSource DataSource = this.ResolvedDataSources.get (LookupKey);
Метод DegineCurrentLookupkey возвращает поиск, метод ResolvedDataSources заключается в получении источника данных с карты на основе LookupKey. ResolvedDataSources и DeginedCurrentLookupkey определены следующим образом:
частная карта <объект, DataSource> ResolvedDataSources; Защищенный абстрактный объект DegineCurrentLookupkey ()
Увидев приведенное выше определение, есть ли у нас какие -то идеи? ResolvedDataSources - это тип карты. Мы можем спасти MasterDataSource и Slavedatasource на карту следующим образом:
| ключ | ценить |
| владелец | MASTERDATASOURCE |
| раб | Slavedatasource |
Мы пишем класс DynamicDatasource, который наследует AbstractroutingDataSource и реализует его метод DetreineCurrentLookupkey (), который возвращает ключ, мастер или раб карты.
Хорошо, после того, как я так много сказал, я немного раздражаю. Посмотрим, как это достичь.
Технология, которую мы хотим использовать, была упомянута выше. Давайте сначала посмотрим на определение аннотации:
@Retention (artenentionpolicy.runtime) @target (elementtype.method) public @Interface DataSource {string value ();} Нам также необходимо реализовать абстрактный класс Spring Class AbstractroutingDataSource, который должен реализовать метод DegineCurrentLookupkey:
Общедоступный класс DynamicDataSource расширяет AbstractroutingDataSource {@Override защищенного объекта DegineCurrentLookupkey () {// TODO Auto Generated Method Stub return DynamicDataSourceholder.getDatasouce (); }} открытый класс DynamicDatasourceholder {public static final threadlocal <string> holder = new Threadlocal <String> (); public static void putdatasource (string name) {holder.set (name); } public Static String getDatasouce () {return holder.get (); }} Из определения DynamicDataSource он возвращает значение DynamicDataSourcelder.getDatasouce (). Нам нужно позвонить в метод DynamicDataSourceholder.putDataSource (), когда программа работает, и присвоить ему значение. Ниже приведена основная часть нашей реализации, то есть часть AOP. DataSourCeasepect определяется следующим образом:
открытый класс DataSourCeaspect {public void до (joinpoint point) {object target = point.getTarget (); String method = point.getSignature (). GetName (); Класс <?> [] Classz = target.getClass (). GetInterfaces (); Class <?> [] ParameterTypes = ((MethodingGust) point.getSignature ()) .getMethod (). GetParameterTypes (); try {method m = classz [0] .getMethod (метод, параметрический); if (m! = null && m.isannotationpresent (dataSource.class)) {dataSource data = m .getannotation (dataSource.class); DynamicDataSourceholder.UptDataSource (data.value ()); System.out.println (data.value ()); }} catch (Exception e) {// todo: обрабатывать исключение}}}Для удобства тестирования я определил 2 базы данных, Mock Mock Master Library, Test Mock Slave Library, Shop и Test Table Structures одинаковы, но данные различны, а конфигурация базы данных выглядит следующим образом:
<bean id="masterdataSource" > <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/shop" /> <property name="username" value="root" /> <property name="password" value = "yangyanping0615"/> </bean> <bean id = "slavedatasource"> <name = "name =" driverclassname "value =" com.mysql.jdbc.driver "/> <name =" url "value =" jdbc: mysql: //127.0.0.1: 3306/test "/> <protect"/> <propect "/> <protect"/> <protect "/> <propect"/> <propect "/> <protect". value = "root" /> <name = "password" value = "yangyanping0615" /> < /bean> <beans: bean id = "dataSource"> <name = "targetDataSources"> <Map Key-Type = "java.lang.String"> <!-write-> witch key = "master-value-ref =" MasterDatas " /> <>-write-> <inpit key =" value-ref = "MasterDatas"! key = "slave" value-ref = "slavedatasource"/> </map> </property> <name = "defaultTargetDataSource" ref = "MasterDataSource"/> </beans: bean> <bean id = "transactionManager"> <свойство = "DataSource" Ref = "DataSource"/> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean> </bean? -> <Bean id = "sqlSessionFactory"> <name = "name =" dataSource "ref =" dataSource " /> <name =" configlocation "value =" classPath: config /mybatis-config.xml " /> < /bean>
Добавить конфигурацию AOP в конфигурацию пружины
<!-Настройте аннотацию базы данных AOP-> <Aop: AspectJ-autoproxy> < /aop: AspectJ-autoproxy> <Beans: Bean id = "manyDatasourceaspect" /> <aop: config> <aop: аспект id = "c" ref = "manydatasousepect"> <aop: pointcut id = "tx =" com.air.shop.mapper.*.*(..)) "/> <aop: перед pointcut-ref =" tx "method =" перед "/> </aop: аспект> </aop: config> <!-Настроить аннотацию базы данных AOP->
Ниже приведено определение Mybatis usermapper. Для удобства тестирования вход считывает главную библиотеку, а список пользователей читает библиотеку рабов:
публичный интерфейс usermapper {@datasource ("Master") public void add (пользователь пользователь); @Datasource ("Master") public void update (пользователь пользователя); @Datasource ("Master") public void delete (int id); @Datasource ("Slave") public user loadbyid (int id); @Datasource ("Master") public user loadbyname (string name); @Datasource ("Slave") public list <user> list ();}Хорошо, запустите наше затмение, чтобы увидеть эффект, введите администратор имени пользователя и войдите в систему, чтобы увидеть эффект
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.