Hoy en día, los sistemas de comercio electrónico a gran escala utilizan principalmente tecnología de separación de lectura y escritura a nivel de base de datos, que es una base de datos maestra y múltiples bases de datos de esclavos. La biblioteca maestra es responsable de las actualizaciones de datos y la consulta de datos en tiempo real, y la biblioteca de esclavos es responsable de la consulta de datos que no son de tiempo real. Debido a las aplicaciones reales, la base de datos lee más y escribe menos (la frecuencia de la lectura de datos es alta y la frecuencia de actualización de datos es relativamente pequeña), y la lectura de los datos suele ser más larga y ocupa más CPU en el servidor de la base de datos, lo que afecta la experiencia del usuario. Nuestro enfoque habitual es extraer la consulta de la biblioteca principal, usar múltiples bibliotecas de esclavos y usar el equilibrio de carga para reducir la presión de consulta de cada biblioteca de esclavos.
El objetivo de usar tecnología de separación de lectura y escritura es reducir de manera efectiva la presión en la biblioteca maestra y distribuir solicitudes de datos de consulta de usuarios a diferentes bibliotecas de esclavos, asegurando así la robustez del sistema. Echemos un vistazo al fondo del uso de la separación de lectura-escritura.
A medida que el negocio del sitio web continúa expandiéndose, los datos continúan aumentando y más usuarios, la presión en la base de datos se vuelve cada vez mayor. Métodos tradicionales, como: la base de datos o la optimización de SQL básicamente no pueden cumplir con los requisitos. En este momento, la estrategia de separación de lectura y escritura se puede usar para cambiar el status quo.
Específicamente en el desarrollo, ¿cómo lograr fácilmente la separación de lectura y escritura? Hay dos métodos de uso común:
1 El primer método es el método más utilizado, que es definir dos conexiones de base de datos, uno es MasterDataSource y el otro es SlavedataSource. Al actualizar los datos, leemos el MasterDataSource y al consultar los datos, leemos el SlavedataSource. Este método es muy simple, por lo que no entraré en detalles.
2 El segundo método de conmutación de fuente de datos dinámico es tejer dinámicamente la fuente de datos en el programa cuando el programa se ejecuta, para elegir leer la biblioteca maestra o la biblioteca de esclavos. Las principales tecnologías utilizadas son: anotación, AOP de primavera, reflexión. El método de implementación se describirá en detalle a continuación.
Antes de introducir el método de implementación, prepararemos algunos conocimientos necesarios, la clase de primavera abstructingdataSource
La clase AbstrutingDataSource se ha agregado después de la primavera 2.0. Primero veamos la definición de AbstrutingDataSource:
La copia del código es la siguiente:
Public Abstract Class AbstrutingDataSource extiende AbstractDataSource implementos InitializingBean {}
AbstrutingDataSource hereda AbstractDataSource, que es una subclase de DataSource. DataSource es la interfaz de origen de datos de javax.sql, definida de la siguiente manera:
La interfaz de datos públicas de la interfaz extiende CommondataSource, Wrapper { /** * <p> intenta establecer una conexión con la fuente de datos que * este <code> DataSource </code> Object representa. * * @return Una conexión a la fuente de datos * @Exception SQLException si se produce un error de acceso a la base de datos */ Connection getConnection () lanza SQLException; /** * <p> intenta establecer una conexión con la fuente de datos que * este <code> DataSource </code> Object representa. * * @param Nombre de usuario El usuario de la base de datos en cuyo lado se está * haciendo * @param contraseña la contraseña del usuario * @return una conexión a la fuente de datos * @exception sqlexception si se produce un error de acceso a la base de datos * @since 1.4 */ conexión getConnection (string username, string contraseña) arroja sqlexception;} La interfaz de fuente de datos define dos métodos, los cuales están obteniendo conexiones de base de datos. Echemos un vistazo a cómo AbstrutingDataSource implementa la interfaz DataSource:
Public Connection getConnection () lanza SQLException {return DetetEnTargetDataSource (). GetConnection (); } Public Connection getConnection (String UserName, String Password) lanza SQLException {return DetetETARGetDataSource (). GetConnection (nombre de usuario, contraseña); } Obviamente, es llamar a su propio método DetermineTargetDataSource () para obtener la conexión. El método DetermineTargetDataSource se define de la siguiente manera:
DataSource protegido DetermineTargetDataSource () {afirmo.notnull (this.ResOlvedDataSources, "enrutador DataSource no inicializado"); Object BurectUpKey = DetetInECRENTLOWNUpKey (); DataSource dataSource = this.resolvedDataSources.get (seardUpKey); if (dataSource == null && (this.lenientfallback || showupKey == null)) {dataSource = this.resolvedDefaultDataSource; } if (dataSource == null) {tirar nueva ilegalStateException ("no se puede determinar el dataSource de destino para la tecla de búsqueda [" + seakupkey + "]"); } return dataSource; }Lo que más nos importa es las siguientes dos oraciones:
Object LookUpKey = DetetInEcRentLlookUpkey (); DataSource DataSource = this.resOlvedDataSources.get (SeakUpKey);
El método DetermineCurrentLoPLOUPKEY devuelve la tecla de búsqueda, el método resueltoDataSources es obtener la fuente de datos del mapa basada en SucearoPkey. resueltoDataSources y determinados CurrentLoPlowUpkey se definen de la siguiente manera:
mapa privado <objeto, dataSource> resuelveDataSources; Objeto abstracto protegido DetermineCurrentLlookUpkey ()
Después de ver la definición anterior, ¿tenemos algunas ideas? ResolvedDataSources es el tipo de mapa. Podemos salvar a MasterDataSource y SlavedataSource en el mapa, de la siguiente manera:
| llave | valor |
| maestro | MasterDataSource |
| esclavo | SlavedataSource |
Estamos escribiendo una clase DynamicDataSource que herede AbstrutingDataSource e implementa su método DetermineCurrentLoPlookUpkey (), que devuelve la clave, el maestro o el esclavo del mapa.
De acuerdo, después de decir tanto, soy un poco molesto. Veamos cómo lograrlo.
La tecnología que queremos usar se ha mencionado anteriormente. Primero veamos la definición de anotación:
@Retention (retentionPolicy.Runtime) @Target (elementType.method) public @Interface DataSource {String Value ();} También necesitamos implementar la clase abstracta abstracta de Spring, DataSource, que es implementar el método DetermineCurrentLoPlookUpkey:
La clase pública DynamicDataSource extiende AbstrutingDataSource {@Override Objeto protegido DetermineCurrentLlookUpKey () {// TODO Método Generado Autorgenerado retorno DynamicDataSourceHolder.getDataSouce (); }} clase pública DynamicDataSourceHolder {public static final ThreadLocal <String> Holder = new ThreadLocal <String> (); public static void putDataSource (nombre de cadena) {holder.set (nombre); } public static string getDataSouce () {return holder.get (); }} De la definición de DynamicDataSource, devuelve el valor DynamicDataSourceHolder.getDataSouce (). Necesitamos llamar al método DynamicDataSourceHolder.putDataSource () cuando el programa se está ejecutando y asignarle un valor. La siguiente es la parte central de nuestra implementación, es decir, la parte AOP. El DataSourCeSpect se define de la siguiente manera:
public class dataSourCeAspect {public void antes (unión de punto de unión) {Object Target = Point.GetTarget (); Method de cadena = Point.getSignature (). GetName (); Clase <?> [] Classz = target.getClass (). GetInterfaces (); Clase <?> [] ParametertyPes = ((Methodsignature) Point.getSignature ()) .getMethod (). GetParametertyPes (); intente {método m = classz [0] .getMethod (método, parametertypes); if (m! = null && m.isannotationPresent (dataSource.class)) {dataSource data = m .getAnnotation (dataSource.class); DynamicDataSourceHolder.putDataSource (data.Value ()); System.out.println (data.Value ()); }} Catch (Exception e) {// tODO: manejar excepción}}}Para la comodidad de las pruebas, definí 2 bases de datos, la biblioteca maestra simulada, la biblioteca de esclavos simulados, las estructuras de taller y mesa de prueba son las mismas, pero los datos son diferentes, y la configuración de la base de datos es la siguiente:
<bean id = "masterDataSource"> <Property name = "DriverClassName" value = "com.mysql.jdbc.driver" /> <propiedad name = "url" value = "jdbc: mysql: //127.0.0.0.1: 3306 /toking" /> <nombre de propiedad = "usame" valor = "root" /> <nombre de propiedad contraseña " value = "yangyanping0615"/> </bean> <bean id = "slavedataSource"> <propiedad name = "controladorclassname" value = "com.mysql.jdbc.driver"/> <propiedad name = "url" valor = "jdbc: mysql: //127.0.0.1: 3306/test"/> <name de propiedad = " /> <Property Name = "Password" Value = "Yangyanping0615" /> </le beans> <beans: bean id = "dataSource"> <propiedad name = "targetDataSources"> <map key-type = "java.lang.string"> <!-Write-> <Entrada Key = "Master" Valor-REF = "MasterDataSource" /> <! value-ref = "slavedataSource"/> </sp> </propiety> <Property name = "DefaultTargetDataSource" ref = "masterDataSource"/> </frijoles: bean> <bean id = "transaccionManager"> <Property name = "dataSource" ref = "dataSource"/> </e bean> <!-Configure SQLSessionSession id = "SQLSessionFactory"> <Property Name = "DataSource" ref = "DataSource" /> <Property Name = "configLocation" value = "classpath: config /mybatis-conconfig.xml" /> </ bean>
Agregue la configuración de AOP a la configuración de resorte
< com.air.shop.mapper.*.*(..)) "/> <aop: antes de pointcut-ref =" tx "método =" antes "/> </aop: aspecto> </aop: config> <!-Configure la anotación de la base de datos AOP->>
La siguiente es la definición de mybatis usermapper. Para la comodidad de las pruebas, Iniciar sesión lee la biblioteca maestra y la lista de usuarios lee la biblioteca de esclavos:
interfaz pública usermapper {@dataSource ("maestro") public void add (usuario de usuario); @DataSource ("Master") Public Void Update (usuario del usuario); @DataSource ("maestro") public void Eliminar (int id); @DataSource ("esclavo") Public User LoadByid (int id); @DataSource ("maestro") Public User LoadByName (nombre de cadena); @DataSource ("esclavo") Lista pública <serem> list ();}Ok, ejecute nuestro eclipse para ver el efecto, ingrese el administrador de nombre de usuario e inicie sesión para ver el efecto
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.