Spring对mongoDB分布式数据库整合

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似的格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:

面向集合存储,易存储对象类型的数据。
模式自由。
支持动态查询。
支持完全索引,包含内部对象。
支持查询。
支持复制和故障恢复。
使用高效的二进制数据存储,包括大型对象(如视频等)。
自动处理碎片,以支持云计算层次的扩展性。
支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
文件存储格式为BSON(一种JSON的扩展)。
可通过网络访问。
所谓“面向集合”(Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。Nytro MegaRAID技术中的闪存高速缓存算法,能够快速识别数据库内大数据集中的热数据,提供一致的性能改进。

模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。

存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各种复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized Document Format)。

Spring boot JPA实现

每次开发基本上都是使用mybatis,对于hibernate,估计也忘了差不多。今天来重温了一下hibernate的配置实现。

第一步,肯定是配置文件:

/**
 * Created by alan on 2018/6/18.
 */
@Configuration
public class HibernateConfig {

    private String driver = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
    private String username = "root";
    private String password = "root";

    public HibernateConfig(){
    }

    @Bean
    public BasicDataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setInitialSize(5);
        dataSource.setMaxIdle(100);
        dataSource.setMaxOpenPreparedStatements(100);

        dataSource.setCacheState(true);
        dataSource.setMaxTotal(1000);
        dataSource.setTestWhileIdle(true);
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTimeBetweenEvictionRunsMillis(3600000L);
        dataSource.setMinEvictableIdleTimeMillis(1800000L);
        dataSource.setTestOnBorrow(true);
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");

        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect");
        properties.setProperty("hibernate.show_sql","true");
        properties.setProperty("hibernate.format_sql","true");
        properties.setProperty("hibernate.auto","update");

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setPersistenceUnitName("SpringJPA");
        factoryBean.setJpaVendorAdapter(adapter);
        factoryBean.setDataSource(this.dataSource());
        factoryBean.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
        factoryBean.setValidationMode(ValidationMode.NONE);

        /**
         * scan @Entity
         */
        factoryBean.setPackagesToScan("com.example.demo.model","com.example.demo.repository");
        //factoryBean.setMappingResources("com/example/demo/repository/resource/User.hbm.xml");
        factoryBean.setJpaProperties(properties);
        return factoryBean;
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager(){
        return new JpaTransactionManager(this.entityManagerFactory().getObject());
    }

    @Bean
    public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor(){
        return new PersistenceAnnotationBeanPostProcessor();
    }
    
}

配置文件由dateSource、LocalContainerEntityManagerFactoryBean、PlatformTransactionManager组成,改有的都有了,现在来实现DAO层,emmmmm,本人比较懒,直接在service层里直接写代码了,如下:

public class TestByHibernateServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(TestByHibernateServiceImpl.class);

    @PersistenceContext
    private EntityManager manager;

    @Resource
    private LxUserMapper userMapper;

    public TestByHibernateServiceImpl() {
    }

    public List<LxUserModel> getAll() {
        Query query = manager.createNativeQuery("SELECT *  FROM lx_user ORDER BY id DESC",LxUserModel.class);
        return query.getResultList();
    }

    public LxUserModel getRow() {
//        return manager.createQuery("SELECT a  FROM LxUserModel a ORDER BY id DESC",LxUserModel.class).setMaxResults(1).getSingleResult();
        return userMapper.getRow();
    }

    public int add(LxUserModel userModel) {
        manager.persist(userModel);
        return userModel.getId();
    }

哇塞,跟昨天写的那篇文章比,正篇肯真简短,没错大部分代码都是EntityManager去实现了,很多人包括我都因为懒,不去写自己的DAO实现,而去用开源的,如果有时间还是建议自己实现或看一下EntityManager的原理。

/**
 * Created by alan on 2018/6/18.
 */

@Repository
public interface LxUserMapper extends JpaRepository<LxUserModel,Integer> {

    @Query(value = "SELECT * FROM lx_user ORDER BY id DESC limit 1",nativeQuery = true)
    LxUserModel getRow();
}

 

下面提供一个例子,在真实场景中,查询数据可是千奇百怪,所以按照自己的思维封装了几个通用的方法,当然啦,肯定是使用了EntityManager:

/**
 * Created by alan.luo on 2017/10/22.
 */

public abstract class AbstractDefaultRepository<E extends Serializable> extends AbstractDefaultBaseRepository<E> {

    @PersistenceContext
    private EntityManager manager;

    /**
     * get all the data.
     * @param page
     * @param where
     * @param order
     * @param isDesc
     * @return
     */
    @Override
    public List<E> getAll(int page, List<PredicatePojo> where, String order, boolean isDesc) {
        CriteriaBuilder builder = this.manager.getCriteriaBuilder();
        CriteriaQuery<E> query = builder.createQuery(this.entityClass);

        Root<E> root = query.from(this.entityClass);
        CriteriaQuery<E> select = query.select(root);
        if (order != null && !"".equals(order)){
            if (isDesc){
                select.orderBy(builder.desc(root.get(order)));
            }else {
                select.orderBy(builder.asc(root.get(order)));
            }
        }

        select.where(getListPredicate(where,builder,root));

        TypedQuery<E> typedQuery = this.manager.createQuery(select);
        typedQuery.setFirstResult((page - 1) * ConstantInit.PAGE_SIZE);
        typedQuery.setMaxResults(ConstantInit.PAGE_SIZE);
        return typedQuery.getResultList();
    }

    /**
     * search all the data.
     * @param page
     * @param condition
     * @param order
     * @param isDesc
     * @return
     */
    @Override
    public PagePojo<E> search(int page, List<PredicatePojo> condition, String order, boolean isDesc){

        CriteriaBuilder builder = this.manager.getCriteriaBuilder();
        CriteriaQuery<Long> query = builder.createQuery(Long.class);

        Root<E> root = query.from(this.entityClass);
        CriteriaQuery<Long> select = query.select(builder.count(root));

        select.where(getListPredicate(condition,builder,root));

        long total = this.manager.createQuery(select).getSingleResult();

        PagePojo<E> pages = new PagePojo<E>((long) page,total);
        pages.setList(this.getAll(page,condition,order,isDesc));
        return  pages;
    }

    @Override
    public E getRowById(int id) {
        return this.manager.find(this.entityClass,id);
    }

    @Override
    public void add(E o) {
        this.manager.persist(o);
    }

    @Override
    public void update(E o) {
        this.manager.merge(o);
    }

    @Override
    public void remove(E o) {
        this.manager.remove(o);
    }

    @Override
    public int removeById(int id) {
        CriteriaBuilder builder = this.manager.getCriteriaBuilder();
        CriteriaDelete<E> q = builder.createCriteriaDelete(this.entityClass);

        return this.manager
                .createQuery(q.where(builder.equal(q.from(this.entityClass).get("id"),id)))
                .executeUpdate();
    }

    /**
     *
     * List<PredicatePojo> where = new ArrayList<>();
     *  where.add(new PredicatePojo("id","81", Criteria.lt));
     *  where.add(new PredicatePojo("age","10", Criteria.gt));
     *
     * List<PredicatePojo> where = new ArrayList<>();
     * if (userName != null){
     *     userName = "%" + userName + "%";
     *     List<PredicatePojo> like = new ArrayList<>();
     *     like.add(new PredicatePojo("username",userName, Criteria.like));
     *     like.add(new PredicatePojo("mobile",userName, Criteria.like));
     *     like.add(new PredicatePojo("email",userName, Criteria.like));
     *
     *     PredicatePojo pojo = new PredicatePojo();
     *     pojo.setLikeObj(like);
     *     pojo.setCriteria(Criteria.like);
     *     where.add(pojo);
     * }
     *
     *
     *
     * parser predicate.
     * @param where
     * @param builder
     * @param root
     * @return
     */
    protected Predicate[] getListPredicate(List<PredicatePojo> where,CriteriaBuilder builder,Root<E> root){

        Predicate[] predicates = new Predicate[where.size()];
        Predicate[] like;

        if (where != null && where.size() > 0){
            Predicate p = null;

            for (int i = 0; i < where.size();i++){

                Criteria ca = where.get(i).getCriteria();
                switch (ca){
                    case equal:
                        p = builder.equal(root.get(where.get(i).getKey()),where.get(i).getValue());
                        break;
                    case notEqual:
                        p = builder.notEqual(root.get(where.get(i).getKey()),where.get(i).getValue());
                        break;
                    case isNull:
                        p = builder.isNull(root.get(where.get(i).getKey()));
                        break;
                    case isNotNull:
                        p = builder.isNotNull(root.get(where.get(i).getKey()));
                        break;
                    case gt:
                        p = builder.gt(root.get(where.get(i).getKey()),Double.valueOf(where.get(i).getValue()));
                        break;
                    case lt:
                        p = builder.lt(root.get(where.get(i).getKey()),Double.valueOf(where.get(i).getValue()));
                        break;
                    case ge:
                        p = builder.ge(root.get(where.get(i).getKey()),Double.valueOf(where.get(i).getValue()));
                        break;
                    case le:
                        p = builder.le(root.get(where.get(i).getKey()),Double.valueOf(where.get(i).getValue()));
                        break;
                    case isFalse:
                        p = builder.isFalse(root.get(where.get(i).getKey()));
                        break;
                    case isTrue:
                        p = builder.isTrue(root.get(where.get(i).getKey()));
                        break;
                    case not:
                        p = builder.not(root.get(where.get(i).getKey()));
                        break;
                    case like:
                        like = new Predicate[where.get(i).getLikeObj().size()];
                        for (int j = 0; j < where.get(i).getLikeObj().size();j++){
                            like[j] = builder.like(root.get(where.get(i).getLikeObj().get(j).getKey())
                                    ,where.get(i).getLikeObj().get(j).getValue());
                        }
                        p = builder.or(like);
                        break;
                    case notLike:
                        like = new Predicate[where.get(i).getLikeObj().size()];
                        for (int j = 0; j < where.get(i).getLikeObj().size();j++){
                            like[j] = builder.notLike(root.get(where.get(i).getLikeObj().get(j).getKey())
                                    ,where.get(i).getLikeObj().get(j).getValue());
                        }
                        p = builder.and(like);
                        break;
                }

                predicates[i] = p;
            }
        }
        return predicates;
    }

}

重温了一下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 – >当内存使用达到阈值的时候,所有引起申请内存的命令会报错。

 

 

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