金沙国际平台登录-金沙国际会员登录

热门关键词: 金沙国际平台登录,金沙国际会员登录

并且可以在delete语句中控制每批删除的数据量

博主做过比较多项目的archive脚本编写,对于这种删除数据的脚本开发,肯定是一开始的话用最简单的一个delete语句,然后由于部分表数据量比较大啊,索引比较多啊,会发现删除数据很慢而且影响系统的正常使用。然后就对delete语句进行按均匀数据量分批delete的改写,这样的话,原来的删除一个表用一个语句,就可能变成几十行,如果archive的表有十几个甚至几十个,那我们的脚本篇幅就非常大了,增加了开发和维护的成本,不利于经验比较少的新入职同事去开发archive脚本,也容易把注意力分散到所谓分批逻辑中。

前言

  Session: 是Hibernate持久化操作的基础,提供了众多的数据库操作方法,如save(),update(),delete()。。。etc,用于完成对象的增加,修改,删除等方法.

  后面代码中使用到的HinernateUtil类:是用于构建SessionFactory(Hibernate提供的获取session的工厂类)的一个封装类,在前面的文章SSH初体验系列--Hibernate--1--环境配置及demo中有详细代码,可自行查看.

3.1因为有了SQL语句,迟早都要执行,所以先编写执行该SQL语句的代码。执行该SQL语句的代码应该放在“数据访问层”(编写数据访问层)
在数据访问层,将来可能执行很多的sql语句,不同的Sql语句可能操作不同的表,所以我们要为不同的表建不同类,在某个类中,都是关于操作某张表的Sql语句。

根据这种情况,本周博主刚好在工作过程中,总结并编写了一个自动分批删除数据的模板,模板固定不变,只需要把注意力集中放在delete语句中,并且可以在delete语句中控制每批删除的数据量,比较方便,通过变量组装模板sql,避免每个表就单独写一个分批逻辑的重复代码,化简为繁,增加分批删除一个表指定数据的话只需要增加几行代码就可以。

一) 增(C)

4.编写业务逻辑层
4.1首先编写一个操作特定表的业务逻辑层类XxxxxBll
4.2编写对应的方法
4.3根据表现层的需求,确定业务访问层类的方法该怎么编写(确定参数和返回值)

demo1:不带参数,根据表tmp_Del删除表A对应ID的数据。

   方式三:QBC(Query By Criteria)查询;

      1)Hibernate 5.2版本之前(暂时还没有核实是5.2之前的哪一个版本开始),

        使用QBC查询,通常有3个步骤:

          1.用Session实例的createCriterria()方法创建Criteria对象c;

          2.使用Restrictions工具类的相关方法为创建的对象c设置查询条件。

            常见的方法有: a) Restrictions.eq = 等于;

                    b) Restrictions.allEq = 使用Map、key/value进行多个等于的对比;

金沙国际平台登录 ,                    c) Restrictions.gt = 大于;

                    d) Restrictions.ge = 大于等于;

                    e) Restrictions.ct = 小于;

                    f)  Restrictions.le = 小于等于;

                    g)  Restrictions.between = 对应SQL的between子句;

                    h) Restrictions.like = 对应SQL的like 子句;

                    i) Restrictions.in = 对应SQL 的in子句;

金沙国际会员登录 ,          3.使用对象c的list()方法执行查询,获取结果;

       2) Hibernate 5.2版本时,createCriteria()方法已经过时了,新版中使用的是链式的查询语句(类似C#中的linq to sql,还有现在android中的rxjava,看来,链式编程以其优美的代码风格,便于维护的特性,越来越成为潮流)

        下面放一段核心代码 (可能因为h5.2版本较新,关于createCriteria()替代方法的查询结果,在百度上暂时很难找到,这个地方也是费了老大劲了. ):

@org.junit.Test
    public void get_qbc(){
        Session session= HibernateUtil.openSession();
        //在Hibernate 5.2中,此方法过时了
        //Criteria criteria=session.createCriteria(Feedback.class);

        //用新的替代方法
        CriteriaBuilder cBuilder=session.getCriteriaBuilder();
        CriteriaQuery<Feedback> cQuery= cBuilder.createQuery(Feedback.class);
        Root<Feedback> feedbackRoot=cQuery.from(Feedback.class);


        //1.select all records
        CriteriaQuery<Feedback> select = cQuery.select(feedbackRoot);
        TypedQuery<Feedback> typedQuery = session.createQuery(select);
        List<Feedback> resultlist = typedQuery.getResultList();
        /*
        最终打印的sql语句:
        Hibernate: select feedback0_.id as id1_2_, feedback0_.username as username2_2_, feedback0_.content as content3_2_, feedback0_.sendTime as sendTime4_2_ 
            from feedback feedback0_
        **/

        //2.Ordering the records
        CriteriaQuery<Feedback> select1 = cQuery.select(feedbackRoot);
        select1.orderBy(cBuilder.asc(feedbackRoot.get("id")));
        TypedQuery<Feedback> typedQuery1 = session.createQuery(select1);
        List<Feedback> resultlist1 = typedQuery1.getResultList();
        /*
        最终打印的sql语句:
        Hibernate: select feedback0_.id as id1_2_, feedback0_.username as username2_2_, feedback0_.content as content3_2_, feedback0_.sendTime as sendTime4_2_ 
            from feedback feedback0_ order by feedback0_.id asc
        * */


        //3.where select条件筛选查询
        CriteriaQuery<Feedback> select2 = cQuery.select(feedbackRoot);
        select2.orderBy(cBuilder.asc(feedbackRoot.get("id")));
        select2.where(cBuilder.ge(feedbackRoot.get("id"),60));
        TypedQuery<Feedback> typedQuery2 = session.createQuery(select2);
        List<Feedback> resultlist2 = typedQuery2.getResultList();
        /*
        最终打印的sql语句:
        Hibernate: select feedback0_.id as id1_2_, feedback0_.username as username2_2_, feedback0_.content as content3_2_, feedback0_.sendTime as sendTime4_2_ 
            from feedback feedback0_ where feedback0_.id>=60 order by feedback0_.id asc
        * */


        System.out.println("result ok");
    }

 

区分层次的目的即为了“高内聚,低耦合”的思想。

总结

二) 查(R)

public bool IncAge(int sid)
{

demo2:带参数,根据Date字段是否过期删除表B对应数据。

  2.批量添加数据;

    可以通过for循环,将数据统一添加到一级缓存session中,再commit到数据库;

金沙国际平台登录 1金沙国际平台登录 2

@org.junit.Test
    public void saveMany(){
        //创建对象
        List<Feedback> feedbackList=new ArrayList<>();
        for(int i=0;i<10;i++){
            Feedback newItem=new Feedback();
            newItem.setUsername("andew"+i);
            newItem.setContent("测试单条插入"+i);
            newItem.setSendTime(new Timestamp(System.currentTimeMillis()));
            feedbackList.add(newItem);
        }
        Session session=null;
        Transaction tx=null;
        try{
            //获取session对象
            session= HibernateUtil.openSession();
            //开启事务
            tx=session.beginTransaction();
            //执行保存,此时只是保存到Session缓存中,并没有同步到数据库
            Feedback feedback=null;
            for(int i=0;i<feedbackList.size();i++){
                feedback=feedbackList.get(i);
                session.save(feedback);
            }
            //提交事务,就缓存同步到数据库
            tx.commit();
        }catch(Exception e){
            //异常时,事务回滚
            tx.rollback();
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            //释放session
            session.close();
        }
    }

for循环执行session的save方法

    如果数据量不大时,或者对性能没有极致的追求时,这种方法还ok;但是当批量插入数据量较大时,这个方式的弊端就体现出来了.

    弊端主要有两点:a,循环向Session添加,修改数据时,Session对象自身开辟的一级缓存会不断被消耗,直到耗尽(outOfMemoryError);

             b,通过在hibernate.cfg.xml文件配置"显示sql语句"

        <!--显示SQL语句-->
        <property name="show_sql">true</property>

              再跟踪打印的SQl语句,很容易就发现,内部其实还是执行了n(n=数据量)次的插入操作,而不是一次语句执行,在性能上,可想并不是很好. 对于喜欢追求代码性能的小伙伴,这是让人难以忍受的,如鲠在喉...

Hibernate: select max(id) from feedback
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Hibernate: insert into feedback (username, content, sendTime, id) values (?, ?, ?, ?)
Disconnected from the target VM, address: '127.0.0.1:59399', transport: 'socket'

Process finished with exit code 0

    解决方案:a,对于内存溢出,可以在代码中进行判断,每隔n条,释放一次缓存;并且在hibernate.xfg.xml中配置每次提交sql的数量

<property name="hibernate.jdbc.batch_size">10</property>

// 每处理20条清空缓存
session.save(newItem);
if (i%20 == 0) {
    session.flush();
    session.clear();
}

        b.若想在性能上有所提升,可以绕过Hibernate Api,直接使用jdbc api来做批量插入;

金沙国际平台登录 3金沙国际平台登录 4

@org.junit.Test
    public void saveJdbc(){
        //创建对象
        List<Feedback> feedbackList=new ArrayList<>();
        for(int i=0;i<20;i++){
            Feedback newItem=new Feedback();
            newItem.setUsername("andew"+i);
            newItem.setContent("测试单条插入"+i);
            newItem.setSendTime(new Timestamp(System.currentTimeMillis()));
            feedbackList.add(newItem);
        }
        String insertSql="insert into feedback (username, content, sendTime) values (?, ?, ?)";

        Session session=null;
//        Transaction tx=null;
        try{
            session= HibernateUtil.openSession();
            //tx=session.beginTransaction();
            session.doWork(new Work() {
                @Override
                public void execute(Connection connection) throws SQLException {
                    //这里面就得到connection了
                    PreparedStatement stmt=connection.prepareStatement(insertSql);
                    //方式1:自动提交
                    /*connection.setAutoCommit(true);
                    for(int i=0;i<feedbackList.size();i++){
                        stmt.setString(1,"andrew"+1);
                        stmt.setString(2,"test content "+i);
                        stmt.setTimestamp(3,new Timestamp(System.currentTimeMillis()));
                        stmt.execute();//此语句,每次执行,都会将一条数据插入到db
                    }*/

                    //方式2:批量提交
                    connection.setAutoCommit(false);
                    for(int i = 0; i<feedbackList.size();i++) {
                        stmt.setString(1,"andrew"+1);
                        stmt.setString(2,"test content "+i);
                        stmt.setTimestamp(3,new Timestamp(System.currentTimeMillis()));
                        stmt.addBatch();
                        if (i % 10 == 0) {
                            stmt.executeBatch();
                            connection.commit();//此处执行一次db插入操作
                        }
                    }
                    stmt.executeBatch();
                    connection.commit();
                }
            });
            ////注意:此时不能再用事务,会报错:org.hibernate.TransactionException: Unable to commit against JDBC Connection
            // tx.commit();
        }catch(Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            //释放session
            session.close();
        }
    }

jdbc批量插入数据

    其中有几个地方需要注意:

      a,connection对象的获取:

a)过时方式:session.connection();
     但是这个方法Hibernate不推荐使用,The method connection() from the type         Session is deprecated
    在3.3以后的版本中已经被废除了。

b)Session.doWork;
    3.3官方的替代方法是用Session.doWork(Work work);
    传入的参数work是一个接口,可以:
    HibernateFactory.getSession().doWork(
          new Work() {
            public void execute(Connection connection) {
              // 这里面就得到connection了,    
                }
          }
        );   

      b.代码中的"方式2,批量提交",就是我们最终想要的高性能的答案;

5.表现层调用业务层实现功能。

以上所述是小编给大家介绍的sql server编写archive通用模板脚本实现自动分批删除数据,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Ok,今天比较详细的学习一下hibernate的C(create)、R(read)、U(update)、D(delete) 相关api...

//确定返回值:执行完毕该sql语句,数据库返回了什么,那么该方法原样返回该值,不要做判断

-- ===== 1 分批archive模板 =======================================================--/* 说明:1. 组装的archive语句为:@sql = @sql_Part1 + @sql_Del + @sql_Part22. 组装的参数@parameters为:@parameters = @parameters_Base + 自定义参数3. 传入参数:@strStepInfo 需要print的step信息4. archive逻辑专注于@sql_Del,而非分散于分批。*/declare @parameters nvarchar(max) = '', @parameters_Base nvarchar(max) = N'@strStepInfo nvarchar(100)', @sql nvarchar(max) = '', @sql_Part1 nvarchar(max) = N'declare @iBatch int = 1, --批次 @iRowCount int = -1 --删除行数,初始为-1,后面取每批删除行数@@ROWCOUNTprint convert(varchar(50), getdate(), 121) + @strStepInfowhile @iRowCount  0begin print ''begin batch:'' print @iBatch print convert(varchar(50), getdate(), 121) begin try begin tran', @sql_Del nvarchar(max) = '' --@sql_Del脚本需要根据实际情况在后续脚本中自行编写, @sql_Part2 nvarchar(max) = N' select @iRowCount = @@rowcount commit tran end try begin catch rollback tran print ''-- Error Message:'' + convert(varchar, error_line()) + '' | '' + error_message() end catch waitfor delay ''0:00:01'' --延时 print convert(varchar(50), getdate(), 121) print ''end batch'' select @iBatch = @iBatch + 1end'-- ===== 2 demo1:archive 表A =======================================================select @parameters = @parameters_Base + '' --如果有需要增加自定义参数,在这里加,例如@parameters = @parameters_Base + ', @ArchiveDate datetime', @sql_Del = ' delete top (50000) tc_Del from 表A tc_Del inner join tmp_Del cd on cd.ID = tc_Del.ID'select @sql = @sql_Part1 + @sql_Del + @sql_Part2print @sqlexec sp_executesql @sql, @parameters, N' 2 archive 表A'-- ===== 3 demo2:archive 表B =======================================================select @parameters = @parameters_Base + ', @ArchiveDaate datetime' --如果有需要增加自定义参数,在这里加,例如@parameters = @parameters_Base + ', @ArchiveDate datetime', @sql_Del = ' delete top (50000) from 表B where Date  @ArchiveDate'select @sql = @sql_Part1 + @sql_Del + @sql_Part2print @sqlexec sp_executesql @sql, @parameters, N' 3 archive 表B', @ArchiveDate

后言

  呼~~总算能松口气了。。。

  真正写的时候,才发现, "crud",叫起来多么简单的一个单词,中间的文章何其多,深挖起来,几天几夜也说不完; hibernate一个流行的框架,里面的内容又是何其多,博主实在是不敢继续继续深入下去了,否则这篇文章发表不知要到何年何月去了(哈哈~~开个玩笑)...

  文章内容虽然不深,不过博主是在用心写,里面的每一段代码,都是测试运行,确认无误的...(自己受够了网上前言不搭后语的demo代码,骂过... 同样原因,可不想自己也被参考了文内代码的人在背后骂^_^)如果大家发现什么问题,也欢迎评论,有问题的地方,我会及时修正;

  文章写着挺耗时的,不过楼主会坚持下去。理由只有两个:1.如果你也刚开始学Hibernate,本文能让你觉得多少有些收获,我就会觉得自己的没有做无用功;  2.博主自己忘了的时候,业可以回头来翻看;

  也欢迎大家关注,共同学习,共同进步.

 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利;

本文出自:博客园--别问是谁

金沙国际平台登录 5

本文由金沙国际平台登录发布于金沙国际平台登录,转载请注明出处:并且可以在delete语句中控制每批删除的数据量

您可能还会对下面的文章感兴趣: