多线程模拟高并发情况redis 与数据库缓存不一致

import com.mysql.jdbc.Connection;
import entity.User;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.sql.*;
import java.util.LinkedList;

/**
 * @描述  队列解决高并发,redis,缓存与数据库不一致问题
 * @参数 $
 * @返回值 $
 * @创建人 yufeng.lin@ucarinc.com
 * @创建时间 $
 * @修改人和其它信息
 */



public class TestQueueSolution {


    //获得mysqlconnection
    public Connection getMysqlConn() {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/redistest?useSSL=false";
        String username = "root";
        String password = "root";
        Connection conn = null;
        try {
            Class.forName(driver); //classLoader,加载对应驱动
            conn = (Connection) DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public User execQuerySql(Connection connection,String sqlStr, LinkedList parms) throws SQLException {
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        pstmt = connection.prepareStatement(sqlStr);
        for (int i = 1 ; i <= parms.size() ; i++ ){
            ///记得 后面跟的是 i-1
            pstmt.setObject(i,parms.get(i-1));
        }
        resultSet = pstmt.executeQuery();
        User user = null;
        while (resultSet.next()){
            user = new User();
            System.out.println("----------------");
            user.setId(resultSet.getInt("id"));
            user.setAge(resultSet.getInt("age"));
            user.setBirthday(resultSet.getDate("birthday"));
            user.setName(resultSet.getString("name"));
        }
        return user;

    }


    //执行sql 以及参数
    public Integer exeuUpdateTheSqlWithParms(Connection connection,String sql,LinkedList parms) throws SQLException {
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        pstmt = connection.prepareStatement(sql);
        //设置参数
        for (int i = 1 ; i <= parms.size(); i++){
            pstmt.setObject(i,parms.get(i-1));
        }
        Integer count = pstmt.executeUpdate();
        return  count;
    }



        //删除redis并延迟更新数据的线程
        class UpdateRedisDataBaseThread implements Runnable{
            public String redisKey;
             //每个线程获取自己的connection
            public Connection connection;
            //数据库 名字
            public String parmName;
            //设置数据年龄
            public Integer age;

            public UpdateRedisDataBaseThread(String redisKey, String parmName, Integer age) {
                this.redisKey = redisKey;
                this.parmName = parmName;
                this.age = age;
            }

            @Override
            public void run() {
                //每个线程自己 的 redis 客户端
                Jedis jedis  =  new Jedis("127.0.0.1",6379);
                //如果存在则进行删除
                if ( jedis.exists(this.redisKey) ){
                    System.out.println("del a value from redis :" + this.redisKey);
                    jedis.del(this.redisKey);
                }
                //模拟延迟更新数据库
                //设置参数
                this.connection = getMysqlConn();
                String sqlStr = "update t_user set age = ? where name = ?";
                LinkedList parm_link = new LinkedList();
                parm_link.add(age);
                parm_link.add(parmName);
                try {
                    //休眠一秒
                    System.out.println("UpdateRedisDataBaseThread sleep 3s");
                    Thread.sleep(3000);
                    Integer count  =   exeuUpdateTheSqlWithParms(connection,sqlStr,parm_link);
                    System.out.println("UpdateRedisDataBaseThread update database count:"+count);

                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        //直接更改数据库的线程
        class SelectThread implements  Runnable{
            //每个线程获取自己的connection
            public Connection connection;
            //查询参数
            public String parmName;
            //查询结果
            public String queryResult;

            public SelectThread(String parmName) {
                this.parmName = parmName;
            }

            @Override
            public void run() {
                //每个线程自己 的 redis 客户端
                Jedis jedis  =  new Jedis("127.0.0.1",6379);
                //如果redis存在则直接得到值
                if (jedis.exists(parmName)){
                    System.out.println("SelectThread can not get value parm:" + this.parmName);
                    this.queryResult = jedis.get(parmName);
                }else {
                    //缓存没有则到数据库查询
                    this.connection = getMysqlConn();
                    String sqlStr = "select * from t_user where name = ?";
                    LinkedList parm_link = new LinkedList();
                    parm_link.add(parmName);
                    try {
                        User user  =   execQuerySql(connection,sqlStr,parm_link);
                        if ( user != null ){
                            this.queryResult  = user.toString();
                            //--将结果写到redis
                            System.out.println(Thread.class.getName()+" parm " + this.parmName  +" set a vlaue to redis!");
                            jedis.set(this.parmName,this.queryResult);
                        }

                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }

        }



        @Test
        public void test() throws InterruptedException {
            //冲突的记录
            String cfkName = "liming01";
            //第一条请求-执行更新操作的线程
            UpdateRedisDataBaseThread drud = new UpdateRedisDataBaseThread(cfkName,"liming01",66);
            //并发第二条请求 - 执行查询操作的线程
            SelectThread udbt = new SelectThread(cfkName);
            new Thread(drud).start();
            //休眠一秒-模拟其它操作
            Thread.sleep(2000);
            //第二个线程开始查询
            new Thread(udbt).start();
            //主线程休眠10s
            Thread.sleep(10000);//休眠20s

        }



}

没有更多推荐了,返回首页