重温了一下JdbcTemplate读取数据库的例子

JdbcTemplate需要是一个DataSource实例去实现数据库链接,如下面代码:

private BasicDataSource dataSource;
private JdbcTemplate template;

public TestServiceImpl() {
    dataSource = new BasicDataSource();
    dataSource.setDriverClassName(driver);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);

    template = new JdbcTemplate(dataSource);
}

Spring提供了很多数据访问模板,这里使用的是JDBC,当然你也可以使用,比如orm.jpa.jpaTemplate、orm.jdo.JdoTemplate等。

访问模板实例化好了,接下来就是代码的实现,这里会给出3个例子,getAll、getRow、add。取全部,取一行,插入一行数据,直接看代码:

public List<LxUserModel> getAll() {
    RowMapper<List<LxUserModel>> rowMapper = new RowMapper<List<LxUserModel>>() {
        @Nullable
        @Override
        public List<LxUserModel> mapRow(ResultSet rs, int i) throws SQLException {

            List<LxUserModel> list = new ArrayList<>();

            ResultSetMetaData metaData = rs.getMetaData();
            int closNum = metaData.getColumnCount();

            do {
                LxUserModel m = new LxUserModel();
                m.setId(rs.getInt(1));
                m.setUsername(rs.getString(2));
                m.setLoginPassword(rs.getString(3));
                m.setNickname(rs.getString(4));
                m.setRealName(rs.getString(5));
                m.setEmail(rs.getString(6));
                m.setMobile(rs.getString(7));
                m.setSex(rs.getString(8));
                m.setAge(rs.getInt(9));
                m.setCreateTime(rs.getInt(10));
                list.add(m);

            } while (rs.next());

            return list;
        }
    };
    List<LxUserModel> list = template.queryForObject("SELECT * FROM `lx_user` WHERE 1 ORDER BY id DESC", rowMapper, (Object[]) null);

    return list;
}

调用模板方法queryForObject,返回的数据是一个List对象,这里需要我们实现RowMapper接口,并在mapRow方法中实现数据的组装。看完这里,如果你可以举一反三,那么不管是getRow还是getOne,我觉得对你而言都是很简单。下面来看看取一行的代码:

public LxUserModel getRow() {
    RowMapper<LxUserModel> rowMapper = new RowMapper<LxUserModel>() {
        @Nullable
        @Override
        public LxUserModel mapRow(ResultSet rs, int i) throws SQLException {

            LxUserModel m = new LxUserModel();
            m.setId(rs.getInt(1));
            m.setUsername(rs.getString(2));
            m.setLoginPassword(rs.getString(3));
            m.setNickname(rs.getString(4));
            m.setRealName(rs.getString(5));
            m.setEmail(rs.getString(6));
            m.setMobile(rs.getString(7));
            m.setSex(rs.getString(8));
            m.setAge(rs.getInt(9));
            m.setCreateTime(rs.getInt(10));
            return m;
        }
    };
    LxUserModel object = template.queryForObject("SELECT * FROM `lx_user` WHERE 1 ORDER BY id DESC limit 1", rowMapper, (Object[]) null);

    return object;
}

同样实现了RowMapper接口,只是返回的方法不一样,简单吧?

现在来看看add的方法,插入一行数据,意味着需要执行一条SQL语句。

public int add(LxUserModel userModel) {

    String sql = "INSERT INTO `lx_user`(`username`, `loginPassword`, `nickname`, `createTime`) VALUES ('%s','%s','%s','%s')";
    String finalSql = String.format(sql, userModel.getUsername(), userModel.getLoginPassword(), userModel.getNickname(), (System.currentTimeMillis() / 1000));

    logger.info("sql {}", finalSql);
    class StatementCallback2 implements StatementCallback<Integer> {

        @Nullable
        @Override
        public Integer doInStatement(Statement statement) throws SQLException, DataAccessException {
            return statement.execute(finalSql) ? 1 : 0;
        }
    }
    template.execute(finalSql);

    class ResRowMapper implements RowMapper<Integer> {

        @Nullable
        @Override
        public Integer mapRow(ResultSet resultSet, int i) throws SQLException {
            return resultSet.getInt("id");
        }
    }

    return template.queryForObject("select id  from `lx_user` where 1 order by id desc limit 1", Integer.class);
}

代码很直接粗暴,直接执行execute方法,这个方法是不会返回数据的,但是如果我们需要读取到刚刚插入数据的Id怎么办?这里返回使用
queryForObject方法只读取最后一行数据的id,并返回出去。

日志提取分析工具(java源码)

最近有个项目,是硬件结合的,硬件上传到服务器的日志,每天数百万条,有时候某个设备出问题了,因为日志的数据很混乱,很难查出具体的原因。

所以写了这个工具,主要是提高日志分析的效率,可以通过关键词提取日志数据。

工具使用了多线程、I/O等技术,本人技术有限,所以只能写到这样子,测试过很多次。

测试出来的数据:400MB的日志,5个线程:96~97秒完成分割,分割出来的日志大小大同小异,为什么不把分割出来的日志合并呢?因为线程的启动时间不是顺序的,加上本人懒,所以没做了。

不建议使用超过20个线程去处理日志。因为如果是2GB的数据,10个线程去处理,每个线程也只需要处理204.8MB。这个已经是非常快的效率了。

Redis内存淘汰机制

Redis内存淘汰指的是用户存储的一些key可以被Redis主动地从实例中删除,从而产生读miss的情况,那么Redis为什么要有这种功能?

这就是我们需要探究的设计初衷,Redis最常见的两种应用场景为缓存和持久存储,首先要明确的一个问题是内存淘汰策略更适合于那种场景?是持久存储还是缓存?

内存的淘汰机制的初衷是为了更好地使用内存,用一定的缓存miss来换取内存的使用效率。

redis 官方提供的 conf

https://raw.github.com/antirez/redis/2.2/redis.conf

1.# maxmemory <bytes>

我们可以通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能,至于这个值有什么意义,我们可以通过了解内存淘汰的过程来理解它的意义:

1. 客户端发起了需要申请更多内存的命令(如set)。

2. Redis检查内存使用情况,如果已使用的内存大于maxmemory则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。

3. 如果上面都没问题,则这个命令执行成功。

 

2.# maxmemory-policy volatile-lru

redis 中的默认的过期策略是 volatile-lru 。

设置方式   

config set maxmemory-policy volatile-lru

maxmemory-policy 六种方式:

#volatile-lru – >使用LRU算法删除使用过期集合的key
#allkeys-lru – >在主键空间中,优先移除最近未使用的key。
#volatile-random – >在设置了过期时间的键空间中,随机移除某个key。
#allkeys-random – >在主键空间中,随机移除某个key。
#volatile-ttl – >设置了过期时间的键空间中,具有更早过期时间的key优先移除。
#novaiction – >当内存使用达到阈值的时候,所有引起申请内存的命令会报错。

 

 

Push to origin/master was rejected

错误如下:

Git Pull Failed: fatal: refusing to merge unrelated histories

意思是git拒绝合并两个不相干的东西
此时你需要在打开Git Bash,然后进入相应的目录,然后敲git命令:

$ git pull origin master --allow-unrelated-histories

出现类似于这种信息就说明pull成功了:

$ git pull origin master --allow-unrelated-histories
From gitee.com:alanro/suisuinian__server
 * branch master -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 LICENSE | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 191 insertions(+)
 create mode 100644 LICENSE

然后你可以利用git status查看一下当前仓库的状态,是不是所有的全部add并且commit,如果全部完成,那么此时你就可以将本地仓库中的推送到github中,使用如下的git命令:

$ git push -u origin master

搞定

简单处理GPS漂移计算方法

class test{
   
   private LocationPojo preLocation;

    private List<LocationPojo> nowLocation;

    private Long preTime;
   
   public boolean test(List<LocationPojo> now,LocationPojo pre) {
      this.nowLocation = now;
      this.preLocation = pre;
      

        double distance = 0;//两点坐标点距离
        int tmp = 40;//精准度上行初始阀值(固定)
      
        int AccuracyThresholdUp = tmp;//精准度上行阀值
        int AccuracyThresholdDown = 30;//精准度下行阀值

        int stopCount = 0; //静止状态坐标计数
        int rectCountDown = 0; //坐标在30M围栏内计数
        int rectCountUp = 0;  //坐标在100M围栏外计数
      
        int notCheckUpCount = 0; //超出大围栏计数,不检查精准度

      /*
       *
       * 如果没有上一次的GPS数据,那么直接返回这次的GPS数据。
      **/
        if (this.preLocation() == null){
            this.preLocation(this.nowLocation.get(0));
            this.preTime = this.preLocation().getAddTime();//上一次记录的时间
            return true;
        }

        LocationPojo b = null;

        //循环计数(我这边是每次定位间隔是1秒,每次定位数据达到10条后进入计算,所以有这个循环)
      //就是用10条现在的GPS数据与上一次的GPS数据,进行数据计算。
        for (LocationPojo pojo:this.nowLocation){
            if (b == null){
                b = pojo;
            }

            //判断不是GPS数据,如果不是,改变阀值的上下值
            if (pojo.getProvider().equals(GPS.GPS)) {
                AccuracyThresholdUp = (int)(tmp * 1.5);//网络定位普遍在40以上,所以需要改变精准度的阀值。
            }else{
                AccuracyThresholdUp = tmp;//由于是循环的,所以每次都需要重新赋值。
            }

            //没有速度,或者有速度但是精准度很高,我会把这类的数据归于静止状态(GPS漂移数据)
            if (pojo.getSpeed() <= 0 || (pojo.getSpeed() > 0 && pojo.getAccuracy() > AccuracyThresholdDown)){
                stopCount++;
            }

            //测算距离(测算距离的方法有很多,我现在把它封装成工具类了)
            distance = CommUtils.getLocationDistance(pojo.getLatitude(),pojo.getLongitude(),preLocation.getLatitude(),preLocation.getLongitude());

            //优化速度精准度
            if(pojo.getSpeed() > 0 && distance > 0){
                //距离 / 时间 * 3.6 = 速度(KM)
//                float speed = CommUtils.fromatNumber(distance / ((pojo.getAddTime() - this.preTime) / 1000) * 3.6,null);
//                pojo.setSpeed(speed);
                pojo.setSpeed(CommUtils.formatNumber(pojo.getSpeed().doubleValue(),"#0.00").floatValue());
            }

            //latlnt电子围栏 30 - 100m
            //超出围栏(条件是:lat或者lnt与上一次坐标匹配大于[100m]并且精确度在30m以内,条件成立)
            if (distance > 100){
                notCheckUpCount++;

            //高精准度(GPS数据应该是可靠的)
                if(pojo.getAccuracy() < AccuracyThresholdUp){
                    rectCountUp++;

                    //如果上一次GPS精准度大于这一次,那么次数GPS数据是有效的。
                    if(pojo.getAccuracy() <= preLocation.getAccuracy()){
                        b = pojo;
                    }
                }
            }else if (distance > 30 && pojo.getAccuracy() < AccuracyThresholdUp){
                //如果在电子围栏内,并且精确度在30m以内,条件成立
                rectCountDown++;
                if(pojo.getAccuracy() <= preLocation.getAccuracy()){
                    b = pojo;
                }
            }
            
        }

        //a:在30米的围栏中必须有速度值,而且超出小围栏的计数>=5个,条件成立则正在移动(30M直径的正方形)
        //a1:在100米的围栏中有8个条数据均超出,不管有没有速度,条件均成立(也许他是坐飞机,也许他瞬移)
        double a = getNowLocation().size() * 0.5;
        double a1 = getNowLocation().size() * 0.8;
        if ((stopCount <= 5 && rectCountDown >= a) || rectCountUp >= a1 || (notCheckUpCount == getNowLocation().size() && rectCountUp >= a) || (stopCount >= a && rectCountUp >= a)){
            this.setPreLocation(b);
            this.setPreTime(b.getAddTime());
            return true;
        }
        return false;

    }
}
14041424344118
 
Copyright © 2008-2021 lanxinbase.com Rights Reserved. | 粤ICP备14086738号-3 |