Recentemente, estou fazendo otimização de consulta de balanço de margem. Quando o projeto é iniciado, o saldo precisa ser totalmente carregado no cache local, porque o saldo da margem de todos os pilotos precisa ser totalmente consultado. Para não afetar o desempenho do banco de dados principal, considere deixar a consulta. Portanto, envolve a necessidade de configurar várias fontes de dados em um projeto e ser capaz de alternar dinamicamente. Após alguma exploração, a comutação dinâmica é perfeitamente realizada e o método de configuração é registrado para sua referência.
Idéias gerais de design
O método Spring-Boot+AOP realiza a comutação de fonte de vários dados, herda o abstractroutingDataSource para obter aquisição dinâmica da fonte de dados e especifica fontes de dados usando anotações na camada de serviço.
etapa
1. Configuração de fonte de vários dados
No Application.Properties, nossa configuração é assim
#Master Data Source druid.master.url = jdbc: mysql: // url/masterdb? useunicode = true & caracteryEncoding = utf8 & zerodatetimebehavior = converttonulldruid.master.username = xxxdruid.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-quadery = select 1#da fonte de dados druid.slave.url = jdbc: mysql: // url/slavedb? useunicode = true & caracteryncoding = utf8 & zerodateTimeBeHavior = converttonulldruid.slave.username = xxxdruid.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
Leia a configuração
<!-fonte de dados mestre-> <bean primary = "true" id = "masterdb" init-method = "init" de destruição-method = "close"> <!-url de propriedades básicas, usuário, senha-> <names driver (namesname "value (" com.mysql.jdbc.driver "/> <namesname" "urname =" com.mysql.jdbc. name = "nome de usuário" value = "$ {druid.master.username}"/> <propriedade name = "senha" value = "$ {druid.master.password}"/> <!-configure a inicialização máxima-> <nome da propriedade "" maxactive = "$ {druid.master.Max- name = "maxwait" value = "$ {druid.master.max-wait}"/> <propriedade name = "validationQuery" value = "$ {druid.master.validation-Query}"/> <names name = "testonborrow" = "$ {druid.master.test-on-borrow} primário = "true" id = "escravo" init-method = "init" destruir-method = "close"> <!-Propriedades básicas URL, usuário, senha-> <propriedade name = "driverclassName" value = "com.mysql.jdbc.driver"/> <nome da propriedade = ") value = "$ {druid.slave.username}"/> <propriedade name = "senha" value = "$ {druid.slave.password}"/> <!-Configurar tamanho de inicialização, mínimo e máximo-> <nome da propriedade = "maxactive" = "$ {druid.slave.max-cactive}" name = "maxwait" value = "$ {druid.slave.max-wait}"/> <propriedade name = "validationQuery" value = "$ {druid.slave.validation-query}"/> <names name = "testonborrow" = "$ {druid.slave.test-on-borrow} As anotações na interface de serviço-> <bean id = "DataSource"> <propriedade name = "TargetDataSources"> <map key-type = "java.lang.string"> <Entrada key = "escravo" value-ref = "escravo"/> <key = "Master" valuef = "masterDB"/" name = "defaultTargetDataSource" ref = "masterDB"/> </bean> <!-spring jdbctemplate-> <bean id = "jdbctemplate"> <names name = "DataSource" ref = "DataSource"/> </Bean> <!-Spring Transaction Manager-> idéia "=" ref = "DataSource"/> </bean> <bean id = "transactionTemplate"> <propriedade name = "transactionManager" ref = "transactionManager"/> </i bean> <tx: anotação-drive transaction-manager = "transactionManager" proxy-target-class = "true" ("="/>/"/" id = "sqlsessionFactory"> <propriedade name = "dataSource" ref = "DataSource"/> <Nome da propriedade = "mapperLocations" value = "ClassPath*: mapper-xxxdb/*mapper*.xml"/> </ Bean> </i bean> <names name = "Basepackage") value = "SQLSessionFactory"/> </Sean>2. Fonte de dados dinâmicos
A primavera nos fornece com abstractroutingDataSource, uma fonte de dados com roteamento. Após a herança, precisamos implementar seu determinanteCurrentLookupKey (), que é usado para personalizar o método de roteamento do nome da fonte de dados real. Como salvamos as informações no ThreadLocal, só precisamos retirá -las.
classe pública DynamicDataSource estende abstractrotingDataSource {private logger logger = LoggerFactory.getLogger (this.getClass ()); @Override Protected Object DetermineCurrentLeoveKey () {String DataSource = JDBCContextholder.getDataSource (); Logger.info ("A fonte de dados é {}", DataSource); return DataSource; }}3. Classe de comutação dinâmica de fonte de dados
A comutação dinâmica da fonte de dados é baseada na AOP; portanto, precisamos declarar uma seção AOP e fazer a troca da fonte de dados na frente da seção. Após a conclusão da seção, o nome da fonte de dados é removido.
@Aspecto @pedidos (1) // Defina a ordem de execução da AOP (precisa ser antes da transação, caso contrário, a transação ocorrerá somente na biblioteca padrão) @ComponentPublic Class DataSourCeaspect {private Logger Logger = LoggerFactory.getLogger (this.getClass ()); // Cut Point @PointCut ("Execução (*com.xxx.service. String métod = Point.getSignature (). GetName (); Classe <?> Classz = Target.getClass (); // Obtenha a classe de destino <?> [] ParameterTypes = ((MethodSignature) Point.getSignature ()) .getMethod (). GetParameterTypes (); tente {método m = classz.getMethod (método, parameterTypes); if (m! = null && m.isannotationPresent (myDataSource.class)) {myDataSource Data = m.getannotation (myDatasource.class); Logger.info ("Método: {}, DataSource: {}", m.getName (), data.value (). getName ()); JdbcContextholder.putDataSource (data.value (). GetName ()); // Coloque a fonte de dados no thread atual}} catch (Exceção e) {Logger.error ("Get DataSource Error", e); // master jdbcContextholder.putDataSource (DataSourceType.master.getName ()); // Coloque a fonte de dados no thread atual}} @afterReturning ("aspecto ()") vazio public (junção) {jdbcContextholder.clearDataSource (JONPOint Point) { }}4. Categoria de gerenciamento de fonte de dados
classe pública jdbcContextholder {private final Static Threadlocal <string> local = new Threadlocal <> (); public static void putdataSource (nome da string) {local.set (nome); } public static string getDataSource () {return Local.get (); } public static void clearDataSource () {local.remove (); }}5. Anotações e enumerações da fonte de dados
Quando alteramos as fontes de dados, geralmente o implementamos antes de chamar o método da interface específica, por isso definimos uma anotação de método. Quando a AOP detecta que a anotação está presente no método, ele alterna de acordo com o nome correspondente ao valor na anotação.
@Retention (retentionPolicy.Runtime) @target (elementType.method) public @Interface myDataSource {DataSourCetype Value ();} public Enum DataSourCetype {// Master ("Master"), // Slave ("Slave"); nome de string privado; DataSourceType privado (nome da string) {this.name = name; } public string getName () {return name; } public void setName (nome da string) {this.name = name; }}6. Anotação do ponto de corte
Como nossa fonte de dados dinâmica possui uma biblioteca padrão, se o método for operar a biblioteca padrão, não há necessidade de anotações. Se você deseja operar uma fonte de dados não padrão, precisamos adicionar @mydataSource ("nome de dados de dados") anotação ao método, para que você possa usar a AOP para obter comutação dinâmica.
@ComPonentPublic Classe XXXServiceImpl {@Resource Private XXXMapperext xxxmapperext; @MydataSource (value = DataSourCetype.Slave) Lista pública <BetAll) {return xxxmapperext.getall (); }}O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.