java数据引擎(五):详细使用

来源:互联网 发布:nba2k13捏脸详细数据 编辑:程序博客网 时间:2024/06/03 23:06

1.     xml  SQL操作

上面所述的查询等操作,都是较单纯的数据操作,如果涉及多表关联查询、子查询、判断查询、数据库的特殊语句及函数调用,显然采用之前的方式是不行的。

        数据引擎吸取了mybatis的思想,可以配置sql,但使用过程是简化了的。

虽然增删改也可以采用配置sql实现,但失去了数据引擎的简洁的思想,因为那样的话与mybatis基本没什么两样了。不过下面还是要介绍的。

A.配置

在类路径(如xml)下创建一个扩展名为.sql.xml的文件,这里叫test.sql.xml。

文件的内容像下面这样:

 <?xmlversion="1.0"encoding="UTF-8"?>

<sqlsnamespace="testsql">

     <sqlid="queryList">

       select * from studentwhere sid<![CDATA[>]]>?

     </sql>

     <sqlid="getCount">

          selectcount(*) ct from student where age=18

     </sql>

</sqls>

在上面提到的udbcConfig.xml中将这个sql文件引入:

<dataSource>

      …

</dataSource>

<sqlConfig>

     <sql resource="/xml/test.sql.xml" />

     <!--如果/xml下有多个.sql.xml 文件,使用下面的一行就可以-->

     <sqlresource="/xml/*"/>

</sqlConfig>

 

B. 简单操作

看看如何调用上面test.sql.xml中的两个简单的sql。

String sqlid=”testsql.getCount”// namespace.id

List<Map<String, Object>>list=DataCenter.queryMapList(sqlid);

int count=(Integer)list.get(0).get(“ct”);//获取结果数

 

Object[] args=new Object[] {10};//对应于问号?参数的值

String sqlid=”testsql.queryList”;

List<Map<String, Object>>list=DataCenter.queryMapListParam(sqlid,args);

这是封装为Map的对象集,如果要得到实体对象集,可以这样:

List<Student> result=DataCenter.queryObjectListParam(sqlid, args, Student.class);

需要注意的是,如果表字段与实体的属性名不相同,需要使用别名形式的sql,

例如:selectname ,class_id  classid,age from student,这样,class_id字段的值才会写入到实体类的classId中。

 

如果sql中不带问号?参数,调用方法是:

DataCenter. queryMapList (sqlid);

DataCenter.queryObjectList(sqlid, Student.class);

 

C. 复杂操作

使用配置的sql可以应对任意复杂的业务需求,而且一个配置sql可以根据条件生成若干具体的sql语句,用来当条件的参数与前述的一样,也是Map对象或实体对象,这里没有使用到Param类。能生成多条语句的特性与ibatis的做法一样,用的是动态标签(下面有专门总结),语句中也是使用##或$$分隔参数名,但每个语句只有一个id,没有像ibatis那样的传入、传出参数配置,也没有映射结果map的配置,没条语句的标签都是<sql>,不分select、update、delete 、insert等。

假如有这样的配置sql:

<sql id="dynamicsql">

    select * from studentt

    <dynamicprepend="where">

      <isNotNullproperty="name"prepend="and">

         t.name like'%$name$%'

      </isNotNull>

      <isNotNullproperty="age"prepend="and">

         t.age<![CDATA[<]]>#age#

      </isNotNull>

    </dynamic>

      order by t.sid

</sql>

调用:

Map map = new HashMap();

map.put("name","zhang");

map.put("age", 18);

List<Map<String,Object>> result = DataCenter.queryMapList("testsql.dynamicsql", map);

上面生成的sql是:select * from student t where t.name like'% zhang%' and t.age <18

如果map不放这句:map.put("name", "zhang"),那么生成的语句就是

select * from student t wheret.age <18

如果没有map.put("age", 18),生成的则是select * from student t wheret.name

like '% zhang%'

如果map没有任何键,或者干脆不要参数map,只传入sqlid,那么生成的是:

select * from student

要得到实体结果集(注意字段的属性别名使用)

List<Student> result=DataCenter.queryObjectList(sqlid,map,Student.class);

 

test.sql.xml中加入如下的配置:

<sqlid="insert1">

       insert into student (sid,name,age)values(?,?,?)

</sql>

<sqlid="insert2">

       insert into student (sid,name,age) values(#sid#,#name#,#age#)

</sql>

 以上两个语句都是用来向student插入记录的,调用如下:

       Object[] args=new Object[3];

       args[0]=300;

       args[1]="chengsx";

       args[2]=20;

       intc=DataCenter.exeAdd("testsql.insert1", args);

       Map map=new HashMap();

       map.put("id", 400);

      map.put("name","wang");

       map.put("age", 18);

intc=DataCenter.exeAdd("testsql.insert2", map);//也可使用实体对象做参数

以上两种插入方式的区别在于,前者在构造参数时需要要严格的顺序,后者则没有此限制。

当需要批量插入记录时,可调用exeAddBatch(String sqlId,List<Object[]>paramArgs)

关于修改、删除的方法,与上面类似,不一一写sql了:

//修改操作,record中含有sql里用##$$界定的属性及值

exeEdit(String sqlId,Objectrecord)

//修改操作,record中含有sql里用##$$界定的属性及值,paramValues含占位参数(即?参数)所对应的值

exeEdit(String sqlId,Objectrecord,Object[] paramValues)

//批量修改操作,record中含有sql里用##$$界定的属性及值,paramArgs是多个?参数所对应的值

exeEditBatch(StringsqlId,Object record,List<Object[]> paramArgs)

以下删除方法的参数意义与修改方法的参数是一样的:

exeRemove(String sqlId,Objectrecord)

exeRemove(String sqlId,Objectrecord,Object[] paramValues)

exeRemoveBatch(StringsqlId,List<Object[]> paramArgs)

exeRemoveBatch(StringsqlId,Object record,List<Object[]> paramArgs)

 

xml定义的sql是查询功能时,为了获取其查询的记录数(用于分页),可调用

intcount=getRecordCountBySqlId(sqlid);

这样就不必再定义一个获取记录数的sql了。

 

获取记录数的方法提供了多种重载的形式。

D.配置方式的关联查询

前面提到的关联查询完全通过Param类来实现,也可以像hibernate那样通过配置文件来实现,首先创建文件,tab.maping.xml, (maping.xml是约定使用的扩展名)内容如下:

<?xmlversion="1.0"encoding="UTF-8"?>

<tables>

  <tablename="student">

       <!-- one-to-one -->

     <mapingproperty="schoolClass"relTable="school_class"relClass="test.SchoolClass"

                   srcField="class_id"relField="cid"lazy="true"/>

     <!-- one-to-many -->            

     <mapingproperty="lessionList"relTable="lession"relClass="test.Lession"

            srcField="sid"relField="sid"lazy="false"/>

       <!-- many-to-many使用中间表关联-->

       <!-- srcFieldrelField可以不定义,将自动采用主键名-->

    <mapingproperty="lessonList"relTable="lesson"srcField="sid"relField="lid"middleTable="student_lesson"middleFromField="sid"middleToField="lid"relClass="test.Lesson" lazy="true"/>

</table>

</tables>

在总配置文件udbcConfig.xml中引入上述文件:

<!--关联映射配置-->

<mapingConfig>

   <map resource="/xml/tab.maping.xml"/>

</mapingConfig>

经过这样配置后,当在查询时,引擎会自动加载关联属性,调用方式与其它查询一样,看参考前文。

lazy配置为false时,只有第一层级查询会是即时加载,更深层的查询仍然是延迟加载。

如果lazy的值为false,只有查询单个记录对象时(getMap,getObject),才是即时加载,如果是获取多个对象,仍然是延迟加载。

使用getMap获取结果对象时,如果在Param设置限制字段时,没有包含主键,谈不上延迟加载功能。

获取map数据时,设置延迟加载,如果返回的结果是一条记录,应该转型为Map,而不是List

    如果既在xml配置了关联映射,又在Param中设置了映射,那么以Param的为主,忽略xml的配置,

xml的配置生效时,如果获取的Map结果对象,复合属性的名称采用的就是配置中的指定名称。

 

E.构建动态语句的标签

下面是引擎提供的逻辑元素词,适合于构建复杂的sql语句。其中有的已经在上面的场景中用到了,不难理解。不支持迭代和if形式的语句(而mybatis是支持的)。

@dynamic动态创建。表示其中的内容是否要包含,完全靠传入的参数决定。属性有prepend,其值即为在动态内容前面添加的内容

@isNotNull参数值是否不为空。属性有prepend和property,表示如果property对应的值存在,那么就将isNotNull元素体内容加入到 sql,并在前面增加prepend的值,元素体中的##或$$里的内容替换为property在参数中对应的值。

@isNull  参数值是否为空,与isNotNull相反。

@isEqual参数值是否等于指定值。 属性有prepend、property和 compareValue,即判断参数中property所对应的值是否为compareValue的值,如果是,纳入元素体的内容,替换##或$$中的值。 

@isNotEqual是否不相等。 与isEqual正相反。属性有prepend、 property、compareValue

@isLessThan参数值是否小于指定值。属性有prepend、 property、 compareValue,如果property在参数中的值小于compareValue的值,纳入元素体的内容,替换##或$$中的值。

@isGreaterEqual是否大于等于。和isLessThan相反。属性有prepend、 property、compareValue

@isBetween  介于两个值之间。属性有prepend、 property、compareValue1、compareValue2,即满足compareValue1<=property并<=compareValue2条件时,纳入元素体的内容,替换##或$$中的值。

@isNotBetween不在范围内,与isBetween相反。即property<compareValue1和property>compareValue2时,纳入元素体的内容,替换##或$$中的值。

@isStartWith参数字符串以指定值开头。属性有prepend、 property、 compareValue

@isNotStartWith与isStartWith相反。属性有prepend、 property、compareValue

@isEndWith字符串以指定值结尾。属性有prepend、 property、 compareValue

@isNotEndWith与isEndWith相反。属性有prepend、 property、compareValue

@isLengthEqual字符串长度等于指定的整数值。属性有prepend、 property、 compareValue

@isLengthNotEqual字符串长度不等于指定的整数值。属性有prepend、 property、 compareValue

@isContains  参数值包含指定的字符串。属性有prepend、 property、compareValue

@isNotContains参数值不包含指定的字符串。属性有prepend、 property、 compareValue

@<![CDATA[]]>所有xml的通行作法,表示元数据,这里主要是在sql中含有大于号>或小于号<时使用。

@##和$$的区别,前者会根据参数的类型替换##的内容,即如果是字符串,就替换为'xx';数值型的,替换为xx;日期型的,替换为与特定数据库相应的格式,等等。 而后者则不作类型判断,直接作简单的原样替换。

 

1.     调用存储过程

引擎对存储过程的调用也是很方便的,下面针对几种数据库列出几个例子。不同的库存储过程调用方法是一样的,不同的只是各种过程所需要的参数类型有所区别。

A.   oracle过程

假如有oracle的过程1,需要获得结果集:

CREATE OR REPLACE PROCEDURE sp_oracle1(

    result  OUT  SYS_REFCURSOR

) AS

BEGIN

     OPEN result  FOR  SELECT * from user;

end ;

调用:

int[] out=new int[]{oracle.jdbc.OracleTypes.CURSOR};//定义传出参数的类型

Map map=DataCenter.getByProcedure("sp_oracle1",null,out);

List records=map.get(“result”);// result是存储过程的传出参数的名称

 

Oracle过程2,包含两个传入参数,两个结果集传出参数:

CREATE OR REPLACE PROCEDURE sp_oracle2(

    in_name invarchar2,  --传入参数

    in_age inint,        --传入参数

    res1  OUT SYS_REFCURSOR,--传出结果

    res2  OUT SYS_REFCURSOR --传出结果

) AS

BEGIN

      OPEN  res1 FOR  SELECT * from user where name=in_name;

      OPEN  res2 FOR  SELECT * from user where age>in_age;

end ;

调用:

int[] out=new int[]{oracle.jdbc.OracleTypes.CURSOR,oracle.jdbc.OracleTypes.CURSOR};

Mapobj=DataCenter.getByProcedure("sp_oracle2",new Object[]{"zhang",30},out);

List records1= (List<Map<String,Object>>)obj.get("res1");//第一个结果

List records2= (List<Map<String,Object>>)obj.get("res2");//第二个结果

 

B.    db2过程

假如存储过程,既有in参数,也有out参数,还有inout参数:

CREATE  PROCEDURE sp_db2(

in  nm_in1 VARCHAR(50),

in  nm_in2 varchar(50),

out  uid integer,

inout  uname VARCHAR(50)

)

RESULT SETS 1

LANGUAGE SQL

BEGIN

DECLARE C1 CURSOR WITH RETURN FOR

SELECT * FROM user where name like nm_in1||'%';

OPEN C1;

SELECT id into uid FROM user where name = nm_in2;

select name into uname FROM user where name =uname;

END

调用:

Object[] in=newObject[]{"zhang","liu"};

  int[] out=newint[]{Types.INTEGER};

  Object[][]inout=new Object[][]{{"wang"},{Types.VARCHAR}};

  Mapobj=DataCenter.getByProcedure("sp_db2",in,out,inout);

List records=(List<Map<String,Object>>)obj.get(2);

Int id=obj.get("uid");

Stringname=obj.get("uname");

C.    mysql过程

假如有过程proc_name,根据传入的参数决定查询哪个表:

CREATE PROCEDURE  proc_name(in  parameter integer)

begin

if  parameter=0  then

select * from student ;

else

select * from test ;

end if;

end

调用:

Mapres=DataCenter.getByProcedure("proc_name",new Object[]{0});

List<Map<String, Object>> result=(List<Map<String,Object>>) res.get(1);

 

调用过程的方法中参数的类型只有两种,一种是int数组,一种是Object数组,

前者定义参数的数据类型,后者定义参数的具体值。

在返回的结果map中,key是存储过程中传入参数或传入传出参数的名称,或者是结果集的顺序编号,编号从1开始。如果存储过程无任何参数,但包含结果集,使用按顺序的方式获取所需结果集。如果存储过程没有任何传入传出参数,直接调用即可:

DataCenter.getByProcedure("SP_DBTEST");

      

2.       直接使用原生SQL

在项目开发过程中,有时可能已经有现成的sql语句了;或者业务稍显复杂,单表操作不好实现,但又不想为此单独建一个sql.xml配置文件;或者有的操作根本不涉及到库表,例如,postgreSQL或mysql获取md5的值,select md5(‘abc’),这种情况下,最方便的操作就是调用:getBySql(sql)。

//求abc的md5值(不是每种库都支持该函数)

Object object = DataCenter.getBySql("select  md5('abc')  val");

Map map=(Map) ((List)object).get(0);

String val=( String) map.get(“val”);//获取结果

 

Object object = DataCenter.getBySql("select count(*)  ct  from student");

Map map=(Map) ((List)object).get(0);

int count=(Integer) map.get("ct");//获取结果数

 

Object object = DataCenter.getBySql("select  *  from student");

List list=(List)object;//记录集

 

Object object = DataCenter.getBySql("delete from student where sid=1");

int count=(Integer)object;//删除的记录数

 

Object object = DataCenter.getBySql("drop table test_tab");//删除test_tab表

boolean flag=(Boolean)object;//返回false,表示ddl操作

上面传递的都是简单的语句,但可以是任意的复杂sql,至于返回什么样的结果,完全是基于sql语句来的,可根据需要转型为实际的结果类型。

引擎还提供了一个可以传递参数值的方法:

public static Object getBySql(String sql,Object[] paramValues)

与上面的区别在于,这里面的sql不是完整sql,是含有问号?占位符的,后边的

paramValues传递占位符对应的值。

String sql=”select * from student where name=? and  age>?”;

Object object = DataCenter.getBySql(sql,new Object[]{“张三”,20});//注意20是没引号的

List list=(List)object;//记录集

 

3.       操作视图

如果库中含有视图view,与针对表的操作完全一样,传递视图名即可。至于能否向视图里插入数据等操作,完全与具体的库相关。

0 0
原创粉丝点击