SQL 总结(-)

本文详细介绍了Hibernate的三种查询方式:标准化对象查询(CriteriaQuery)、Hibernate语言查询(HQL)以及原生SQL查询。CriteriaQuery以对象方式查询,易于阅读但不成熟;HQL面向对象,功能强大,支持多态和关联;原生SQL查询直接使用数据库语法,灵活但需要注意SQL注入问题。文章还涵盖了投影、统计、分页、连接查询等操作,并提供了示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                              Hibernate总结(sql,hql)(一)

· Hibernate语言查询(支持hql, 原生SQL查询,标准化对象查询)

  一、标准化对象查询(CriteriaQuery)

    定义:以对象的方式进行查询,将查询语句封装为对象操作。

    优点:可读性好,符合Java程序员的编码习惯。

缺点:不够成熟,不支持投影或统计函数。

//投影查询:用来进行聚合操作,和sql中的聚合类似.求和/求平均值/统计记录数/...等等.获取对象的某些属性(表字段)或属性集合

//统计函数:比如max,sum,min,avg等

Eg:  查询用户名以“J”开头的所有用户:

注意:Expression是快捷键可调出来的,封装好的代表查询的表达式,来做条件,类net.sf.hibernate.expression.Expression定义了获得一些内置的Criterion类型。

 二、Hibernate语言查询(HibernateQuery Language,HQL)

        1. 定义:它是完全面向对象的查询语句,查询功能非常强大,具备多态、关联等特性。

        2. HQL用面向对象的方式生成SQL:

(1)以类和属性代替表和数据列

(2)支持多态

(3)支持各种关联

(4)减少了SQL的冗余

        3.HQL支持所有的关系数据库操作

            连接、投影、聚合、排序、子查询和SQL函数

Eg:查询用户名以“J”开头的所有用户:

一、简单属性查询

        1. 单一属性查询

//返回结果集是属性列表(可用非泛型集合接收(object型);数组就不方便,固定长度,类型要求每个元素也必须一样),元素类型和实体类中的属性类型一致 

Eg:(查询学生的姓名):

 

List students = session.createQuery("select name from Student").list();  

for (Iterator iter=students.iterator(); 

iter.hasNext();

) {  

    //name返回的String类型  

    String name = (String)iter.next();  

  }    

     2. 多个属性查询

//查询多个属性,返回对象数组集合  

//数组元素的类型与查询的属性类型一致  

//数组的长度与select中查询的属性个数一致  

Eg:(查询学生的id和name):

List students = session.createQuery("select id, name from Student").list();  

for (Iterator iter=students.iterator(); iter.hasNext();) {  

    Object[] obj = (Object[])iter.next();  

   }

二、实体对象查询

//返回Student对象的集合  

1.无select关键字:

List students = session.createQuery("from Student").list();  

for (Iterator iter=students.iterator(); iter.hasNext();) {  

    Student student = (Student)iter.next();  

    System.out.println(student.getName());  

}  

        2.无select关键字,使用别名:

List students = session.createQuery("from Student s").list();  

//采用as命名  

List students = session.createQuery("from Student as s").list();  

for (Iterator iter=students.iterator();

 iter.hasNext();

) {  

    Student student = (Student)iter.next();  

    System.out.println(student.getName());  

}  

        3.用select关键字,必须加上别名:

List students = session.createQuery("select s from Student s").list();  

for (Iterator iter=students.iterator(); 

iter.hasNext();

) {  

    Student student = (Student)iter.next();  

    System.out.println(student.getName());  

}    

        4.不支持select * from 语法

【补充】list和iterate的区别(.list()/.iterate()都是query的方法)

     list: 默认情况下list每次都会发出sql语句,list会将数据放到缓存中,而不利用缓存

     iterate:默认情况下iterate利用缓存,如果缓存中不存在会出现N+1问题(发出了N+1条sql语句,1:首先发出查询对象id列表的语句;N:根据id到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句)

   

(1). 采用list查询  

            /** 

             * 采用list查询实体对象会发出一条查询语句,取得实体对象数据 

             *  

             Sql=  select student0_.id as id0_ ,  student0_.name as name0_ ,  

           student0_.createTime as  createTime0_  ,  student0_.classesid as  classesid0_  

              from t_student student0_ 

             

            List students = session.createQuery("from Student").list();  

            for (Iterator iter=students.iterator();

 iter.hasNext();

) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }   

(2). 采用iterator查询  

            /** 

             * 会出现N+1问题,所谓的N+1指的是发出了N+1条sql语句 

               

              1:发出一条查询id列表的语句 

              Sql=:select  student0_.id  as  col_0_0_  from  t_student  student0_ 

             

             2:根据id发出N条加载相关的对象 sql语句

              Sql=: select student0_.id as  id0_0_ ,  student0_.name as name0_0_ ,  

             student0_.createTime  as createTime0_0_ , student0_.classesid as  classesid0_0_  

             from t_student student0_ where  student0_.id = ? 

  

              Iterator iter = session.createQuery("from Student").iterate();  

              while (iter.hasNext()) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }   

(3). 先采用list后采用iterator  

            List students = session.createQuery("from Student").list();  

            for (Iterator iter=students.iterator(); 

iter.hasNext();) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  

            System.out.println("-----------------------------------------------------");  

            /** 

             * 避免了N+1问题 

             

              因为执行list操作后会将数据放到session的缓存中(一级缓存),所以采用iterate的时候 首先会发出一条查询id列表的语句,再根据id到缓存中加载相应的数据,如果缓存中存在与之匹配的数据 则不再发出根据id查询的sql语句,直接使用缓存中的数据 

 Iterate方法如果缓存中存在数据,它可以提高性能,否则出现N+1问题 

            

             

            Iterator iter = session.createQuery("from Student").iterate();  

            while (iter.hasNext()) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  

(4). 两次都采用list  

            List students = session.createQuery("from Student").list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  

            System.out.println("-----------------------------------------------------");  

              

           

              再此发出查询语句 

             

             在默认情况下,每次执行list查询实体对象都会发出查询语句,除非配置了查询缓存 

             虽然一级缓存中存在Student数据,但list不用,所以仍然发出查询语句, 

              

              其实list就是只向缓存中放入数据,而不利用缓存中的数据 

             

            students = session.createQuery("from Student").list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  


条件查询

        1. 拼串

//可以拼串  (但不安全,比如sql注入

            List students = session.createQuery("select s.id, s.name from Student s where s.name like '%0%'").list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Object[] obj = (Object[])iter.next();  

                System.out.println(obj[0] + ", " + obj[1]);  

            }    

 

例子1:statement := "SELECT * FROM users WHERE name = '" +userName + "'; "

将用户名变量(即username)设置为:a' or 't'='t,此时原始语句发生了变化:
SELECT * FROM users WHERE name = 'a' OR 't'='t'; 
如果这种代码被用于一个认证过程,那么这个例子就能够强迫选择一个合法的用户名,因为赋值't'='t永远是正确的。
例子2:a'; DROP TABLE users;SELECT * FROM data WHERE name LIKE '%

这就将最终的SQL语句变成下面这个样子:SELECT * FROM users WHERE name = 'a'; DROP TABLE users; SELECT *FROM DATA WHERE name LIKE '%'; 
将会造成数据库表被删除的严重后果。所以强烈建议大家停止SQL语句拼接(特别是网站应用),采用带参数化存储过程。
注:对于已经完成的ASP.NET网站应用(.net框架下的web应用程序),设计修改代码太多的,可以考虑加入如下代码处理一下,避免被严重注入攻击。可以通过在Global.asax.cs文件中添加过滤关键字的方法来实现 防止 sql 注入攻击(sql injection),代码如下。

       /// 当有数据时交时,触发事件 
     ///  <paramname="sender"> </param> 
    ///  <paramname="e"> </param> 
    protected voidApplication_BeginRequest(Object sender, EventArgs e) 
    { 
    //遍历Post参数,隐藏域除外 
    foreach (string i inthis.Request.Form) { 
            if (i =="__VIEWSTATE") continue; 
           this.goErr(this.Request.Form.ToString()); 
        }

//遍历Get参数。 

foreach (string i inthis.Request.QueryString) 
        { 

this.goErr(this.Request.QueryString.ToString()); 
        }
    }
       ///SQL注入过滤 
       ///  <paramname="InText">要过滤的字符串 </param> 
    ///  <returns>如果参数存在不安全字符,则返回true </returns> 
    public boolSqlFilter(string InText) 
    { 
        string word ="and |exec |insert |select |delete |update |chr |mid |master |or |truncate|char |declare |join |cmd | |' |--";//这里加要过滤的SQL字符 
        if (InText == null) 
            return false; 
        foreach (string i inword.Split(' |')) 
        { 
      if((InText.ToLower().IndexOf(i + " ") > -1)  | | (InText.ToLower().IndexOf(" "+ i) > -1))  { 

 return true; 
        } 
        } 
        return false; 
    } /// 校验参数是否存在SQL字符 
       ///  <paramname="tm"> </param> 
    private voidgoErr(string tm) 
    { 
        if (SqlFilter(tm)) 
        { 
Response.Write(" <script>window.alert('参数存在不安全字符');"+"</"+"script>"); 
        } 
    }

                    .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Object[] obj = (Object[])iter.next();  

                System.out.println(obj[0] + ", " + obj[1]);  

            }  

 

 

分页查询

List students = session.createQuery("from Student")  

                        //从数据库的第几条记录开始  

                        .setFirstResult(1)  

                        //每页显示的记录数  

                        .setMaxResults(2)  

                        .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  

对象导航查询

//查询班级名称包含2的学生,s.classes.name,可直接查询到班级名称  

     List students = session.createQuery("from Student s where s.classes.name like '%2%'")  

                        .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Student student = (Student)iter.next();  

                System.out.println(student.getName());  

            }  

连接查询

        1. 内连接

//查询班级名称和学生名称,join s.classes将两者进行连接  

            List students = session.createQuery("select c.name, s.name from Student s join s.classes c")  

                        .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                 //返回的是对象数组  

                Object[] obj = (Object[])iter.next();  

                System.out.println(obj[0] + ", " + obj[1]);  

            }  

 

2.左连接

List students = session.createQuery("select c.name, s.name from Student s left join s.classes c")  

                        .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Object[] obj = (Object[])iter.next();  

                System.out.println(obj[0] + ", " + obj[1]);  

            }  

 

3.右连接

List students = session.createQuery("select c.name, s.name from Student s right join s.classes c")  

                        .list();  

            for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Object[] obj = (Object[])iter.next();  

                System.out.println(obj[0] + ", " + obj[1]);  

            }  

统计查询

        1. 查询学生人数

//List list = session.createQuery("select count(*) from Student").list();  

            //Long count = (Long)list.get(0);  

            //因为返回的记录数只有一条,所以不使用list,而使用uniqueResult  

            //count返回的类型为Long  

            Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();  

            System.out.println("count=" + count);  

 2.分组统计

String hql = "select c.name, count(s) from Classes c join c.students s group

 by c.name order by c.name";  

            List students = session.createQuery(hql).list();  

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

                Object[] obj = (Object[])students.get(i);  

                System.out.println(obj[0] + ", " + obj[1]);  

            }  

三、Native SQL Queryies(原生SQL查询)

       //就是查表,在数据库可执行成功,方便调试;

     本地SQL查询也叫原生SQL查询(NativeSQL Query)指的是直接使用本地数据库(如Oracle)的SQL语言进行查询。它能够扫清你把原来直接使用SQL/JDBC 的程序迁移到基于 Hibernate应用的道路上的障碍。

 

 

1:mysql:

一次性多行插入单张表

insert into table(column1, column2)values (value1, value2), (value1, value2)

UPDATE 表 SET 字段=SUBSTRING(字段,1,10) WHERE CHAR_LENGTH(SUBSTRING(字段,1,13))=13        把13位的改成10位的

 

:2::账户被锁,需解锁,超级管理员登录,alter user usernameaccount unlock; 如果解锁失败,报用户不存在,在左侧user表里找有无此解锁用户,没有,找个有的登录之后在解锁

3:第一种方法:select current_date;

MySQL> select current_date as Systemtime;
+------------+
| Systemtime |
+------------+
| 2009-07-29 |
+------------+

 

第二种方法:selectnow()

mysql> select now() as Systemtime;
+---------------------+
| Systemtime          |
+---------------------+
| 2009-07-29 19:06:07 |
+---------------------+

 

第三种方法:selectsysdate()

mysql> selectsysdate() as Systemtime;
+---------------------+
| Systemtime          |
+---------------------+
| 2009-07-29 19:06:45 |
+---------------------+

 

 

2:oracle:

1:sql (原生或本地sql)多表连接查询语句

  

//stu是表t_stuinfo的别名stu.stuid是字段属性,stuid: 是给要查询的字段起的别名

  Eg: 

StringBuffer sb = newStringBuffer(

    “ select stu.stuid  stuid ,us.name stuname, "

+ " org.nameoname,spc.name zyname,cl.name claname,gd.name xb,nt.name mz,pt.namezzmm,ls.status zt from  t_lxgl_leavebatchlb"

                   

        + " inner join t_lxgl_leavestu ls”

+ " onlb.id=ls.leavebatchid "

        + " inner join t_stuinfo stu"

        + " on ls.stuid=stu.stuid "

        + " inner join t_user us"

        +"  on stu.userid=us.id "

        + " inner join t_org org"

        + " on stu.orgid=org.id "

        +" inner join t_class cl"

        + " on stu.tclassid=cl.id "

        + " inner join t_specialty spc“

        + " on stu.specialyid=spc.id "

        + " inner join t_gender gd"

        + " on stu.genderid=gd.id "

        + " inner join t_nation nt"

        + " on stu.nationid=nt.id "

        + " inner join t_party pt"

        + " on stu.partyid=pt.id  where 1=1");

2:增:

  (1):一次性单行插入单张表

Insert into表名(列名)values(值)列名

Insert into  cc  values(SEQ_ID.NEXTVAL,'lala',to_date('1991/02/09','yy-mm-ddhh24:mi:ss'))

//Oracle 的 可以为空必须给值

  一次性多行插入单张表

【将现有表数据添加到一个已有表】
insert into <已有的新表> (列名)select <原表列名> from <原表名>


insert into tongxunlu ('姓名','地址','电子邮件') select name,address,email

from Strdents

【直接拿现有表数据创建一个新表并填充】
select <新建表列名> into <新建表名> from <源表名>


select name,address,email into tongxunlu from strdents

 

(2)一次性插入多张表(不分单或多)

1)//很少用这就相当于把t表的数据给t1和t2都各自插入了一遍,但前提是三张表列数一致,列的类型一致列的t表里列的精度还得符合t1,t2的要求(eg:t(number2000),t1(number2),t2(number2))就不符合

insert all into t1 into t2 into t3 select * from t

2)//先把t中大于等于5的取出来插入t1表,在把剩下的t表里的数据大于等于2的取出来插入t2,但前提跟1)一样

insert first when x>=5 then into t1 when x>=2 theninto t2 when x>=1 then into t3 select * from t;

 

3:删除:

delete from <表名> [where <删除条件>]
delete from a where name='开心朋朋' ;    //删除表a中列值为开心朋朋的行

删除主表信息,同时删除子表信息,包括子表的子表,要在相对主表来说每一级主表里做级联cascade=”all”,inverse一般都是TRUE,代表主表有控制权,一般删除子表,主表里子表的相关数据还在

4:修改

     修改表的语句(oracle 修改表的sql语句)

1增加一个列:
ALTER TABLE 表名 ADD(列名 数据类型);

ALTER TABLE emp ADD(license varchar2(256));

2修改一个列的数据类型(一般限于修改长度,修改为一个不同类型时有诸多限制)


ALTER TABLE 表名 MODIFY(列名数据类型);

ALTER TABLE emp MODIFY(weight NUMBER(3,0) NOT NULL);

3给列改名:
ALTER TABLE 表名 RENAME COLUMN 当前列名 TO 新列名;

ALTER TABLE emp RENAME COLUMN abcTO abc_new;

4删除一个列:
ALTER TABLE 表名 DROP COLUMN 列名;

ALTER TABLE emp DROP COLUMN memo;

5将一个表改名:
ALTER TABLE 当前表名 RENAME TO 新表名;

ALTER TABLE client RENAME TO client_new

 

修改数据的语句

UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值

更新某一行中的好几列

Eg:UPDATE Person SET Address = 'Zhongshan23', City = 'Nanjing'

WHERE LastName ='Wilson'

以上一对多级联 一对多级联增加具有很高的可应用性,一对多级联更与删除在较少的场合中可用,一对多级联删除使用时要谨慎,防止误删

多对一级联 多对一的级联操作(再多的里操作一方。然后),应用性极差差(具体csdn收藏里)

////注意不管是本地sql还是hql,传递条件参数为了安全用命名参数,或占位符来传参,拼接的参数不安全

Eg1:if(参数不为空),else{

stringbuffer的对象.append(“  and mgr.id=:id”);

Query.setParameter(“id”,值)

}

Eg2: if(参数不为空),else{stringbuffer的对象.append(“  and mgr.id=?”);

Query.setParameter(0,”值”)

}

Eg3. 使用 :参数名方式批量查询(一般多用于in的查询)且方法要求集合只能是list或set

 

List students = session.createQuery("select s.id, s.name from Student s where s.id

 In ( : usernameList) ")  

         //参数为集合,使用ParameterList传递参数,

              query.setParameterList(“usernameList”,list).list(); 

在 Hibernate 中通过这样的方式将值注入到这个参数中:  

  

List list=new ArrayList();  

  

list.add(“a”);  

  

list.add(“b”);  

    for (Iterator iter=students.iterator(); iter.hasNext();) {  

                Object[] obj = (Object[])iter.next();  

                           }    

 

若传的参数过多,可以放在map里,但map的键必须跟hql或sql语句的别名。属性名一样,把前台传进来的参数给成值,在实现类里用for循环两个for需一一对应上并且得一个list(l)集合来联系

for (String key :map.keySet()) {

        if (map.get(key) != null &&map.get(key) != "") {

                    sb.append("and " +key + "=?");

                    l.add(map.get(key));

 

                }

            }

            String sql = sb.toString();

        );

            Query query =dbSession.createSQLQuery(sql);

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

                query.setParameter(i, l.get(i));

            }

 

            return

//转为map类型在存在list中

query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)

                    .list();

·Hibernate 的命名查询
    命名查询():与HQL的命名查询相似,也可以将本地的SQL查询语句定义在映射文件中,然后像调用一个命名HQL查询一样直接调用命名SQL查询。

在Hibernate中,当我们在查询的时候不得不把HQL语句或者SQL语句写在程序之中。但是我们不想把这些代码写在程序中,所以Hibernate中提供了一种命名查询,就是把HQL语句或者SQL语句配置到实体类的文件(*.hbm.xml)中,这样可以当我们修改程序的时候会更方便,容易扩展。

使用HQL语句的命名查询

例如:在我们进行查询时的代码:

Session session = HibernateSessionFactory.getSession();

String sql = "select * from PetInfo";  

// 使用SQL语句进行查询

Query query = session.createSQLQuery(sql).addEntity(PetInfo.class);

List<PetInfo> petList = query.list();

……

现在,我们不想把String sql = "select * from PetInfo";  该语句放在程序中,所以我们要在PetInfo.hbm.Xml中配置<query>节点,如下:

<hibernate-mapping package="com.aptech.entity">

  <class name="PetInfo" table="PetInfo">

    <id name="petId" type="java.lang.Integer">

      <column name="pet_id"></column>

      <generator class="native"></generator>

    </id>

    <property name="petName" type="java.lang.String">

      <column name="pet_name" length="50" not-null="true"></column>

    </property>

……

<property name="petType" type="java.lang.Integer">

      <column name="pet_type"></column>

    </property>

  </class>

  <query name="getPetInfo">  <!-- name属性是在程序中得到的一个键,其真正的  value是HQL语句 -->

   <![CDATA[from PetInfo]]>   <!-- HQL语句,此时PetInfo是实体类 -->

  </query>

         </hibernate-mapping>

注意:在配置文件时,可以将<query>节点写到<class>节点之内,也可以将之写到<class>节点之外,两者的区别是:在程序中调用时,在<class>内部,调用要用完整的路径名称,包名+实体类名+属性名即com.aptech.entity.PetInfo.getPetInfo; 在<class>外部,则直接在session.getNamedQuery()方法的参数中写getPetInfo.

如下。在查询测试类中使用配置文件中的HQL语句:

/**

 * 命名查询Demo

 */

public void getPetInfo2()

{

Session session = HibernateSessionFactory.getSession();

// 调用配置文件中的getPetInfo

Query query = session.getNamedQuery("getPetInfo");  

List<PetInfo> petList = query.list();

for (PetInfo petInfo:petList)

{

System.out.println(petInfo.getPetName());

}

session.close();

}

以上配置的是HQL语句的查询,当然在配置文件中也支持本地SQL语句的查询,配置<sql-query>、<return>节点即可。

 

 

 

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值