转载请注明 http://www.cnblogs.com/13590/archive/2013/03/01/2938126.html
摘要:本文探讨了iBatis.Net框架的XML数据映射文件各配置节点的含义,并通过CRUD四种对数据库的操作讲解了如何配置数据映射文件和调用方法。
关键词:iBatis.Net;XML;SQL Maps;数据映射
上一节介绍了iBatis.Net的基本情况和运行原理,运行环境中各参数的配置情况。并通过一个实例项目进行了说明。
1 数据映射基础
SQL Maps是这个iBatis.Net框架中最重要的部分,而SQL Maps的核心就在于XML数据映射文件(Data Map XML File)。在XML数据映射文件里可以定义包括要执行各种SQL语句、存储过程、输入参数映射、返回结果映射、缓存机制,并且能通过几种相对比较复杂的配置实现对象之间的关联关系和延迟加载。这也是iBatis.Net区别其它ORM框架而具备更灵活性,更高性能的关键所在。
配置文件可以写得很简单,也可以很复杂。复杂配置文件往往出于更好的设计,更好性能,更好扩展性方面的目的。一个XML数据映射文件主要分为两个部分:模块配置和语句配置。
2 模块配置
2.1 Type Alias节点
定义一个XML数据映射文件中的别名,其好处就是避免过长变量值的反复书写,比如通过typeAlias节点为类"iBatisTest.Domain.Sysuser"定义了一个别名"Sysuser",这样在这个数据映射文件中的其他部分,需要引用"iBatisTest.Domain.Sysuser"类时,只需以其别名替代即可,和SqlMap.config配置文件里面的Alias节点配置一样。定义如:
<alias><typeAlias alias="Sysuser" type="iBatisTest.Domain.Sysuser,iBatisTest" /></alias>
2.2 cacheModel节点
缓存机制是程序开发中经常讨论的一个话题,在实际的系统开发的过程中,总会存在着这样一类数据,它们更新频率很低,然而使用的频率却非常之高。为了提高系统性能,通常将此类数据装入缓存。iBatis.Net也有自己的缓存系机制,它通过cacheModel节点来配置,具体的定义如下:
<cacheModel type="LRU" id="Sysuser-cache" readOnly="true" serialize="false">
<flushInterval hours="24"/>
<flushOnExecute statement="SysuserMap. UpdateSysuser "/>
<property name="CacheSize" value="100"/>
</cacheModel>
type:缓存的类型,iBatis.Net中有4种类型,分别为MEMORY、LRU、FIFO、OSCACHE。
其中MEMORY是内存缓存,LRU是使用最近最少使用策略,FIFO是使用先进先出策略,OSCACHE是通过第三方的缓存插件来实现。
id:是cacheModel的一个标识,标识该缓存的名字,供后面设置使用。
readOnly:指缓存的数据对象是只读还是可读写,默认为"true",即只读,这里的只读并不是意味着数据对象一旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要需重新从数据库读取数据,构造新的数据对象。而readOnly="false"则意味着缓存中的数据对象可更新。
serialize:是否从缓存中读取同一个对象,还是对象的副本。该参数只有在readOnly为false的情况下才有效, 因为缓存是只读的,那么为不同会话返回的对象肯定是一个,只有在缓存是可读写的时候,才需要为每个会话返回对象的副本。
flushInterval:指定缓存自动刷新的时间,可以为hours、minutes、seconds和milliseconds。需要注意的是,这个间隔时间不是时间到了,在缓存里的信息会自动刷新,而是在间隔时间过后,下次查询将不会从缓存中去取值,而会用SQL去查询,同时将查询的结果更新缓存的值。
flushOnExecute:指定在发生哪些操作时,更新缓存。
property:针对cacheModel的额外的一些属性配置,不同type的cacheModel将会有自己专有的一些property配置,如:
FIFO: <property name="CacheSize" value="100" />
LRU: <property name="CacheSize" value="100" />
MEMORY: <property name="Type" value="WEAK" />
当配置好cacheModel之后就可以在后面的语句中使用了,如:
﹤statement id="SelectSysuser" result cacheModel="Sysuser-cache"﹥
SELECT * FROM DEAN.SYSUSER
﹤/statement﹥
2.3 resultMap节点
resultMap从字面理解就是结果集的映射,它将返回的记录与实体对象进行映射,它属于直接映射。如果查询出来的数据集的字段与属性和实体类一致时,我们常用resultClass来替代,它属于隐身映射。通常resultMap比resultClass性能要高。
在使用resultMap时需要注意,如果在resultMap中给出的配置字段,但是返回的数据集却没有返回这个字段,那程序将出抛出异常。相反的,如果返回了一些字段,却没有在resultMap给出配置定义的话,那么那些字段将不会被处理而不会给出任何的提示,相当没有查询出这些字段。具体的定义例子如下:
<resultMaps>
<resultMap id="SysuserResult" >
<result property="Userid" column="USERID" />
<result property="Password" column="PASSWORD" />
<result property="Loginname" column="LOGINNAME" />
<result property="Sex" column="SEX"/>
<result property="Birthday" column="BIRTHDAY"/>
<result property="Idcard" column="IDCARD" />
<result property="Officephone" column="OFFICEPHONE" />
<result property="Familyphone" column="FAMILYPHONE" />
<result property="Mobilephone" column="MOBILEPHONE"/>
<result property="Email" column="EMAIL"/>
<result property="Address" column="ADDRESS"/>
P_SUB VARCHAR2,
P_SENDOR VARCHAR2,
P_RECEIVER VARCHAR2,
P_SERVER VARCHAR2,
P_PORT NUMBER DEFAULT 25,
P_NEED_SMTP INT DEFAULT 0,
P_USER VARCHAR2 DEFAULT NULL,
P_PASS VARCHAR2 DEFAULT NULL,
P_FILENAME VARCHAR2 DEFAULT NULL,
P_ENCODE VARCHAR2 DEFAULT 'bit 7')
AUTHID CURRENT_USER IS
/*
作用:用oracle发送邮件
主要功能:1、支持多收件人。
2、支持中文
3、支持抄送人
4、支持大于32K的附件
5、支持多行正文
6、支持多附件
7、支持文本附件和二进制附件
8、支持HTML格式
8、支持
作者:suk
参数说明:
p_txt :邮件正文
p_sub: 邮件标题
p_SendorAddress : 发送人邮件地址
p_ReceiverAddress : 接收地址,可以同时发送到多个地址上,地址之间用","或者";"隔开
p_EmailServer : 邮件服务器地址,可以是域名或者IP
p_Port :邮件服务器端口
p_need_smtp:是否需要smtp认证,0表示不需要,1表示需要
p_user:smtp验证需要的用户名
p_pass:smtp验证需要的密码
p_filename:附件名称,必须包含完整的路径,如"d:tempa.txt"。
可以有多个附件,附件名称只见用逗号或者分号分隔
p_encode:附件编码转换格式,其中 p_encode='bit 7' 表示文本类型附件
p_encode='base64' 表示二进制类型附件
注意:
1、对于文本类型的附件,不能用base64的方式发送,否则出错
2、对于多个附件只能用同一种格式发送
*/
L_CRLF VARCHAR2(2) := UTL_TCP.CRLF;
L_SENDORADDRESS VARCHAR2(4000);
L_SPLITE VARCHAR2(10) := '++';
BOUNDARY CONSTANT VARCHAR2(256) := '-----BYSUK';
FIRST_BOUNDARY CONSTANT VARCHAR2(256) := '--' || BOUNDARY || L_CRLF;
LAST_BOUNDARY CONSTANT VARCHAR2(256) := '--' || BOUNDARY || '--' ||
L_CRLF;
MULTIPART_MIME_TYPE CONSTANT VARCHAR2(256) := 'multipart/mixed; boundary="' ||
BOUNDARY || '"';
/* 以下部分是发送大二进制附件时用到的变量 */
L_FIL BFILE;
L_FILE_LEN NUMBER;
L_MODULO NUMBER;
L_PIECES NUMBER;
L_FILE_HANDLE UTL_FILE.FILE_TYPE;
L_AMT BINARY_INTEGER := 672 * 3; /* ensures proper format; 2016 */
L_FILEPOS PLS_INTEGER := 1; /* pointer for the file */
L_CHUNKS NUMBER;
L_BUF RAW(2100);
L_DATA RAW(2100);
L_MAX_LINE_WIDTH NUMBER := 54;
L_DIRECTORY_BASE_NAME VARCHAR2(100) := 'DIR_FOR_SEND_MAIL';
L_LINE VARCHAR2(1000);
L_MESG VARCHAR2(32767);
/* 以上部分是发送大二进制附件时用到的变量 */
TYPE ADDRESS_LIST IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
MY_ADDRESS_LIST ADDRESS_LIST;
TYPE ACCT_LIST IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
MY_ACCT_LIST ACCT_LIST;
-------------------------------------返回附件源文件所在目录或者名称--------------------------------------
FUNCTION GET_FILE(P_FILE VARCHAR2, P_GET INT) RETURN VARCHAR2 IS
--p_get=1 表示返回目录
--p_get=2 表示返回文件名
L_FILE VARCHAR2(1000);
BEGIN
IF INSTR(P_FILE, '') > 0 THEN
--windows
IF P_GET = 1 THEN
L_FILE := SUBSTR(P_FILE, 1, INSTR(P_FILE, '', -1) - 1);
ELSIF P_GET = 2 THEN
L_FILE := SUBSTR(P_FILE, - (LENGTH(P_FILE) - INSTR(P_FILE, '', -1)));
END IF;
ELSIF INSTR(P_FILE, '/') > 0 THEN
--linux/unix
IF P_GET = 1 THEN
L_FILE := SUBSTR(P_FILE, 1, INSTR(P_FILE, '/', -1) - 1);
ELSIF P_GET = 2 THEN
L_FILE := SUBSTR(P_FILE,
- (LENGTH(P_FILE) - INSTR(P_FILE, '/', -1)));
END IF;
END IF;
RETURN L_FILE;
END;
---------------------------------------------删除directory------------------------------------
PROCEDURE DROP_DIRECTORY(P_DIRECTORY_NAME VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'drop directory ' || P_DIRECTORY_NAME;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
--------------------------------------------------创建directory-----------------------------------------
PROCEDURE CREATE_DIRECTORY(P_DIRECTORY_NAME VARCHAR2, P_DIR VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'create directory ' || P_DIRECTORY_NAME || ' as ''' ||
P_DIR || '''';
EXECUTE IMMEDIATE 'grant read,write on directory ' || P_DIRECTORY_NAME ||
' to public';
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
--------------------------------------------分割邮件地址或者附件地址-----------------------------------
PROCEDURE P_SPLITE_STR(P_STR VARCHAR2, P_SPLITE_FLAG INT DEFAULT 1) IS
L_ADDR VARCHAR2(254) := '';
L_LEN INT;
L_STR VARCHAR2(4000);
J INT := 0; --表示邮件地址或者附件的个数
BEGIN
/*处理接收邮件地址列表,包括去空格、将;转换为,等*/
L_STR := TRIM(RTRIM(REPLACE(REPLACE(P_STR, ';', ','), ' ', ''), ','));
L_LEN := LENGTH(L_STR);
FOR I IN 1 .. L_LEN LOOP
IF SUBSTR(L_STR, I, 1) <> ',' THEN
L_ADDR := L_ADDR || SUBSTR(L_STR, I, 1);
ELSE
J := J + 1;
IF P_SPLITE_FLAG = 1 THEN
--表示处理邮件地址
--前后需要加上'<>',否则很多邮箱将不能发送邮件
L_ADDR := '<' || L_ADDR || '>';
--调用邮件发送过程
MY_ADDRESS_LIST(J) := L_ADDR;
ELSIF P_SPLITE_FLAG = 2 THEN
--表示处理附件名称
MY_ACCT_LIST(J) := L_ADDR;
END IF;
L_ADDR := '';
END IF;
IF I = L_LEN THEN
J := J + 1;
IF P_SPLITE_FLAG = 1 THEN
--调用邮件发送过程
L_ADDR := '<' || L_ADDR || '>';
MY_ADDRESS_LIST(J) := L_ADDR;
ELSIF P_SPLITE_FLAG = 2 THEN
MY_ACCT_LIST(J) := L_ADDR;
END IF;
END IF;
END LOOP;
END;
------------------------------------------------写邮件头和邮件内容------------------------------------------
PROCEDURE WRITE_DATA(P_CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
P_NAME IN VARCHAR2,
P_VALUE IN VARCHAR2,
P_SPLITE VARCHAR2 DEFAULT ':',
P_CRLF VARCHAR2 DEFAULT L_CRLF) IS
BEGIN
/* utl_raw.cast_to_raw 对解决中文乱码问题很重要*/
UTL_SMTP.WRITE_RAW_DATA(P_CONN,
UTL_RAW.CAST_TO_RAW(CONVERT(P_NAME || P_SPLITE ||
P_VALUE || P_CRLF,
'ZHS16GBK')));
END;
----------------------------------------写MIME邮件尾部-----------------------------------------------------
PROCEDURE END_BOUNDARY(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
LAST IN BOOLEAN DEFAULT FALSE) IS
BEGIN
UTL_SMTP.WRITE_DATA(CONN, UTL_TCP.CRLF);
IF (LAST) THEN
UTL_SMTP.WRITE_DATA(CONN, LAST_BOUNDARY);
END IF;
END;
----------------------------------------------发送附件----------------------------------------------------
PROCEDURE ATTACHMENT(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
MIME_TYPE IN VARCHAR2 DEFAULT 'text/plain',
INLINE IN BOOLEAN DEFAULT TRUE,
FILENAME IN VARCHAR2 DEFAULT 't.txt',
TRANSFER_ENC IN VARCHAR2 DEFAULT '7 bit',
DT_NAME IN VARCHAR2 DEFAULT '0') IS
L_FILENAME VARCHAR2(1000);
BEGIN
--写附件头
UTL_SMTP.WRITE_DATA(CONN, FIRST_BOUNDARY);
--设置附件格式
WRITE_DATA(CONN, 'Content-Type', MIME_TYPE);
--如果文件名称非空,表示有附件
DROP_DIRECTORY(DT_NAME);
--创建directory
CREATE_DIRECTORY(DT_NAME, GET_FILE(FILENAME, 1));
--得到附件文件名称
L_FILENAME := GET_FILE(FILENAME, 2);
IF (INLINE) THEN
WRITE_DATA(CONN,
'Content-Disposition',
'inline; filename="' || L_FILENAME || '"');
ELSE
WRITE_DATA(CONN,
'Content-Disposition',
'attachment; filename="' || L_FI
工作中需要从一个数据库中的表GIS_WEICHAI_DATA_1S中的数据导入到另个一数据库的表GIS_WEICHAI_DATA_1S中,数据库服务器都是远程的<IP分别为: 221.131.228.256 211.161.192.46>!我的实现方法是在本地使用PL/SQL操作两个远程服务器,实现方式如下:
1.
为你需要操作的远程数据库服务器建立本地服务名:
在本地数据库安装文件中,找到$ORACLE_HOME/network/admin/tnsnames.ora文件,
末尾添加
--第一个远程服务器的服务名:MYORACLE1
MYORACLE1 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 221.131.228.256)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = orcl)
)
)
--第一个远程服务器的服务名:MYORACLE2
MYORACLE2 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 211.161.192.46)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = orcl)
)
)
--如果有更多的远程数据库需要同时操作,可以依次增加!
--如果本机用的Windows操作系统,可以使用Oracle自带的Net Manager 工具,以图形化的操作方式来建立服务名!
2.
在本机上使用sysdba的角色登录本地数据库,创建database link:
执行如下sql语句:
--远程服务器一的对应database link
create public database link MYDBLINK1 --可以随便取名,当然,不能是关键字或保留字
connect to dbUserName1 identified by dbpwd1
using ' MYORACLE1';
--远程服务器二的对应database link
create public database link MYDBLINK2 --可以随便取名,当然,不能是关键字或保留字
connect to dbUserName2 identified by dbpwd2
using ' MYORACLE2';
--其中using后面填对应的数据库服务名,dbUserName1,dbpwd1填对应的数据服务器登录名,密码
--删除database link
Drop database link MYDBLINK1; --本例中是MYDBLINK1和MYDBLINK2
3.
操作远程服务器上的表,在要在对应的表后面加上@ linkName(对应的数据库链接名),就跟操作本地数据库中的表差不多,可以从不同数据库服务器中提取数据!很方便!
insert into GIS_WEICHAI_DATA_1S@MYDBLINK1 select * from GIS_WEICHAI_DATA_1S@ MYDBLINK2 where rownum<=10000;
4.
如果需要频繁的使用远程服务器中的表,上面的写法有点烦人,这时候可以考虑为这个表创建一个同义词
create synonym syName for GIS_WEICHAI_DATA_1S@MYDBLINK1;
以后在要使用GIS_WEICHAI_DATA_1S@MYDBLINK1的时候用syName就可以了!
删除同义词的语法为:
drop synonym syName;
5.
查看当前数据库的DB Link;
select * from user_db_links; --用户 DB Link
select * from dba_db_links; --dba DB Link
select * from v$dblink; --当前DB Link
原文:http://blog.csdn.net/tangkai_java/article/details/5831741
本文链接