Implement caching and database consistency dual-write protection

pox file:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.43</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

  Application:

import java.util.HashSet;
import java.util.Set;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
org.springframework.context.annotation.ComponentScan Import; 
Import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 
Import org.springframework.jdbc.datasource.DataSourceTransactionManager; 
Import the org.springframework.transaction.PlatformTransactionManager; 
Import com.roncoo.eshop .inventory.listener.InitListener; 
Import redis.clients.jedis.HostAndPort; 
Import redis.clients.jedis.JedisCluster; 

@EnableAutoConfiguration // Bean automatically loads all necessary application 
class @SpringBootApplication // start 
@ComponentScan // scan packages 
@MapperScan ( "com.roncoo.eshop.inventory.mapper") 
// start entry function 
public class the Application { 
 
	// build the data source 
    @Bean 
    @ConfigurationProperties (prefix =" spring.datasource ") 
    public the dataSource the dataSource () {
        return new DataSource();
    }

     //构建MyBatis的入口类:SqlSessionFactory
    @Bean
    public SqlSessionFactory sqlSessionFactoryBean1() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
        
        return sqlSessionFactoryBean.getObject();
    }
    //构建事务管理器
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
    
    @Bean
	public JedisCluster JedisClusterFactory() {
		Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
		jedisClusterNodes.add(new HostAndPort("192.168.31.19", 7003));
		jedisClusterNodes.add(new HostAndPort("192.168.31.19", 7004));
		jedisClusterNodes.add(new HostAndPort("192.168.31.227", 7006));
		JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
		return jedisCluster;
	}

    //注册监听器    线程池+内存队列初始化
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean(){
    	ServletListenerRegistrationBean servletListenerRegistrationBean=
    			new ServletListenerRegistrationBean();
    	//添加listener
    	servletListenerRegistrationBean.setListener(new InitListener());
    	return servletListenerRegistrationBean;
    }
    
    //SpringBoot 启动入口的方法
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

  

When updating data, based on the unique identification data, the route after the operation, sent to the internal queue of a jvm

When reading data, if the data is not found in the cache, then read the data again to update the cache + operation, after the unique identification in accordance with the route, also sends the same internal queue jvm

A queue corresponds to a worker thread

Each worker thread to get the corresponding serial operation, and then performing a one

In this case, a change of operating data, execute, delete the cache, and then go to update the database, but is not yet complete update

At this time, if a read request over an empty cache read, then the first cache may transmit the request to update the queue, then the backlog in the queue will be, and then waits for the synchronization cache update complete

There is an optimization point, a queue, in fact, more than one update cache request strung together does not make sense, so you can do the filtering, if the queue has been found to have a request to update the cache,
Then you do not update the requested operation came alive again go directly in front of the waiting for the update to complete the requested operation

After that queue corresponding work to be done to modify the database thread on one operation at will to perform an action, that is, the cache update operation, then reads the latest values ​​from the database, and then write cache

If the request waiting time range, to continue the polling can take values ​​found, then return directly; if the waiting time exceeds a certain length of time request, then this time the old value of the current read directly from the database
 
Specific implementation steps:
1, the thread pool + memory queue initialization
ServletContextListener which do, listener, will start along with the entire web application, initialize, initialize the thread pool to build similar
spring boot application, Application, engage a listener registration
 

Guess you like

Origin www.cnblogs.com/sunliyuan/p/11354531.html