Недавно я делаю оптимизацию запросов на маржинальный баланс. Когда проект начинается, баланс должен быть полностью загружен в локальный кэш, потому что баланс маржи всех гонщиков должен быть полностью запрошен. Чтобы не повлиять на производительность основной базы данных, рассмотрите возможность оставить запрос. Таким образом, он включает в себя необходимость настройки нескольких источников данных в проекте и иметь возможность динамически переключаться. После некоторого исследования динамическое переключение идеально реализовано, и метод конфигурации записывается для вашей ссылки.
Общие идеи дизайна
Метод Spring-Boot+AOP реализует многоданную переключение источника, наследует AbstractroutingDataSource для достижения динамического сбора источника данных и определяет источники данных, используя аннотации на уровне сервиса.
шаг
1. Конфигурация многоданных источников
В приложении. Прозрачные, наша конфигурация такая
#Master Data Source druid.master.url = jdbc: mysql: // url/masterdb? useUnicode = true & haremencoding = utf8 & ZerodateTimebehavior = converttonulldruid.master.username = xxdruid.master.password = 123dru id.master.driver-class-name = com.mysql.jdbc.driverdruid.master.max-wait = 5000druid.master.max-active = 100druid.master.test-on-borrow = truedruid.master.validation-query = select 1#из источника данных druid.slave.url = jdbc: mysql: // url/slavedb? useUnicode = true & haremencoding = utf8 & zerodatetimebehavior = convertonulldruid.slave.username = xxdruid.slave.password = 123dru id.slave.driver-class-name = com.mysql.jdbc.driverdruid.slave.max-wait = 5000druid.slave.max-active = 100druid.slave.test-on-borrow = truedruid.slave.validation-query = select 1
Читать конфигурацию
<!-Источник основных данных-> <bean primary = "true" id = "masterdb" init-method = "init" Drest Method = "close"> <!-базовый URL свойства, пользователь, пароль-> <name = "riverclassname" value = "com.mysql.jdbc.driver"/> <property name = "url" value = "$" {druid.master.master. name = "username" value = "$ {druid.master.username}"/> <name = "password" value = "$ {druid.master.password}"/> <!-Конфигурировать максимальную инициализацию-> <Свойство name = "maxactive" value = "$ {druid.master.max --mactive}"/> <! name = "maxwait" value = "$ {druid.master.max-wait}"/> <name = "validationQuery" value = "$ {druid.master.validation-Query}"/> <name = "testonbourrow" value = "$ {Druid.master.test-on-burrow}"/> </bean> <------ primary = "true" id = "slavedb" init-method = "init" destry-method = "close"> <!-базовые свойства URL, пользователь, пароль-> <property name = "driverclassname" value = "com.mysql.jdbc.driver"/> <name = "url" value = "$ {druid.Slave.Url.Url}"/> "usermem. value="${druid.slave.username}"/> <property name="password" value="${druid.slave.password}"/> <!-- Configure initialization size, minimum, and maximum --> <property name="maxActive" value="${druid.slave.max-active}"/> <!-- Configure the time to get the connection waiting timeout --> <property name = "maxwait" value = "$ {druid.slave.max-wait}"/> <name = "validationQuery" value = "$ {Druid.Slave.validation-query}"/> <name = "testonBorw" value = "$ {druid.slave. На аннотациях по интерфейсу сервиса-> <bean id = "dataSource"> <name = "targetDataSources"> <карта ключа типа = "java.lang.string"> <intry-keo = "slave" value-ref = "slavedb"/> <inpit key = value-ref = "masterdb"/> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> </> name = "defaultTargetDataSource" ref = "masterdb"/> </bean> <!-Spring JdBctemplate-> <Bean id = "jdbctemplate"> <name = "dataSource" ref = "dataSource"/> </bean> <!-Spring Transaction Manager-> <bean id = "transactionmanager"> <! "" DataRce verte "=" hAptArce "" dataRse "=" "hAptArce" = "" hAptArce "=" "hAptArce" = "" hAptArce "" "recase recase" ""? /> </bean> <bean id = "transactiontemplate"> <name = "transactionManager" ref = "transactionManager"/> </bean> <tx: Annotation Transaction-Manager = "TransactionManager" Proxy-Target-class = "true" order = "2"/> <! name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath*:mapper-xxdb/*Mapper*.xml" /></bean><bean> <property name="basePackage" value="xxdb.mapper"/> <property name="sqlSessionFactoryBeanName" value = "sqlSessionFactory"/> </bean>2. Динамический источник данных
Spring предоставляет нам AbstractroutingDataSource, источник данных с маршрутизацией. После наследства нам необходимо реализовать его degineCurrentLookupkey (), который используется для настройки метода маршрутизации фактического имени источника данных. Поскольку мы сохраняем информацию в Threadlocal, нам просто нужно ее вывести.
Общедоступный класс DynamicDatasource Extends AbstractroutingDatasource {private logger logger = loggerFactory.getLogger (this.getClass ()); @Override защищенный объект degineCurrentLookupkey () {String dataSource = jdbccontextholder.getDataSource (); logger.info («Источник данных is {}», dataSource); вернуть DataSource; }}3. Класс динамического переключения источника данных
Динамическое переключение источника данных основано на AOP, поэтому нам необходимо объявить раздел AOP и сделать переключение источника данных перед разделом. После того, как раздел завершен, имя источника данных удалено.
@Assive @order (1) // Установить порядок выполнения AOP (необходимо быть до транзакции, в противном случае транзакция будет происходить только в библиотеке по умолчанию) @ComponentPublic Class DataSourCeaspect {Private Logger = loggerFactory.getLogger (this.getClass ()); // cut point @pointcut ("execution (*com.xxx.service.*.*(..))") public void aspious () {} @before ("amess ()") private void до (joinpoint point) {overse = point.getTarget (); String method = point.getSignature (). GetName (); Class <?> Classz = target.getClass (); // Получить целевой класс класса <?> [] ParameterTypes = ((methodignature) point.getSignature ()) .getMethod (). GetParameterTypes (); try {method m = classz.getmethod (метод, параметрические); if (m! = null && m.isannotationpresent (mydatasource.class)) {mydatasource data = m.getannotation (mydatasource.class); logger.info ("method: {}, dataSource: {}", m.getName (), data.value (). getName ()); Jdbccontextholder.putdatasource (data.value (). GetName ()); // Поместить источник данных в текущий поток}} catch (Exception e) {logger.Error («Получить ошибку данных», e); // Master jdbccontextholder.putDataSource (dataSourcetype.master.getName ()); // Поместите источник данных в текущий поток}} @afterReturning ("asmove ()") public void после (joinpoint point) {jdbccontextholder.cleardataSource (); }}4. Категория управления источником данных
открытый класс jdbccontextholder {private final Static Threadlocal <string> local = new Threadlocal <> (); public static void putdatasource (string name) {local.set (name); } public Static String getDatasource () {return local.get (); } public static void clearDatasource () {local.remove (); }}5. Анноции и перечисления источника данных
Когда мы переключаем источники данных, мы обычно реализуем их перед вызовом метода конкретного интерфейса, поэтому мы определяем аннотацию метода. Когда AOP обнаруживает, что аннотация присутствует на методе, он переключается в соответствии с именем, соответствующим значению в аннотации.
@RETENTION (artenmentPolicy.Runtime) @Target (elementType.method) public @Interface myDatasource {dataSourcetype value ();} public enum dataSourcetype {// Master ("Master"), // slave ("Slave"); Приватное название строки; Private DataSourcetype (String name) {this.name = name; } public String getName () {return name; } public void setName (string name) {this.name = name; }}6. Аннотация точки вырезать
Поскольку у нашего динамического источника данных есть библиотека по умолчанию, если метод должен управлять библиотекой по умолчанию, нет необходимости в аннотациях. Если вы хотите управлять источником данных, не являющимся деко, нам нужно добавить аннотацию @mydatasource («имя данных») в метод, чтобы вы могли использовать AOP для достижения динамического переключения.
@Componentpublic class xxxserviceimpl {@resource private xxxmapperext xxxmapperext; @Mydatasource (value = dataSourcetype.slave) Общедоступный список <object> getAll () {return xxxmapperext.getall (); }}Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.