2013年12月11日星期三

.Net处理Oracle中Clob类型字段总结 - 田园里的蟋蟀

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
.Net处理Oracle中Clob类型字段总结 - 田园里的蟋蟀  阅读原文»

  最近在做项目中用到Clob这个字段,Clob是存储无限长字符的Oracle字段,用的时候网上找资料找了好久,内容不是很多,大部分都不能用,当然也有可以用的,测试了不同版本,整理了一下,给大家在做项目的时候以参考。

表操作

  第一种方案很简单,是数据库表中的某个字段是Clob类型,需要对这个表进行增加修改,网上有很多版本,我试了一种最简单的:

    new OracleParameter(":Test", OracleType.Clob,System.Text.Encoding.Unicode.GetByteCount(model.Test)),

  就是在创建参数的时候指定一个长度,为什么这样写,不是很清楚,我试过超过4000字符存储和修改是没什么问题的。下面给参数赋值直接赋值就行了,就那么简单!

参数操作

  第一种是对表中Clob的操作,还有一种情况是,在Oracle中定义的存储过程和函数,参数的类型是Clob类型,如果用第一种方式的话就会报错,字符超过最大,我想是虽然参数类型是Clob但是传过去的是字符,Oracle默认应该是把传过来的值当做字符看待了,第一种不行,就找了另一种实现方法,我们看下:

public static OracleLob GetOracleClob(string strValue)
{
using (OracleConnection connection = new OracleConnection(connectionString))
{
try
{
connection.Open();
string str = strValue;
byte[] array = Encoding.Unicode.GetBytes(str);
if (array.Length % 2 != 0)
{
array
= Encoding.Unicode.GetBytes(str + ' ');
}
OracleCommand lobCmd
= connection.CreateCommand();
// 为访问表定义一个游标 clobvar
string cmdSql = "DECLARE clobvar CLOB;";
cmdSql
+= " begin ";
cmdSql
+= " dbms_lob.createtemporary(clobvar, false, 0); :tempLob:= clobvar; ";
cmdSql
+= " end;";
lobCmd.CommandText
= cmdSql;
lobCmd.Parameters.Add(
new OracleParameter("tempLob", OracleType.Clob)).Direction = ParameterDirection.Output;
lobCmd.ExecuteNonQuery();

// 利用事务处理(必须)
OracleTransaction tx = connection.BeginTransaction();
lobCmd.Transaction
= tx;

// 定义一个临时变量
OracleLob tempLob = (OracleLob)lobCmd.Parameters["tempLob"].Value;
tempLob.BeginBatch(OracleLobOpenMode.ReadWrite);
tempLob.Write(array,
0, array.Length);
tempLob.EndBatch();
// 提交事务
tx.Commit();
return tempLob;
}
catch (Exception e)
{
throw e;
}
}
}

  调用:

parameters[0].Value = DbHelperOra.GetOracleClob(TestString);

  大家看代码可能明白一些,这里我说下自己的理解,先定义一个Byte,然后拼一个输出Clob类型的字符串,在Oracle执行后输出,然后把Byte写入输出的Clob变量,然后提交事务,我觉得得到的这个Clob类型才是真正的Clob类型,是和Oracle那边是一致的。这边有一个重要的是字符的编码,注意下要和Oracle那边要一致!

  


本文链接:http://www.cnblogs.com/xishuai/p/3469871.html,转载请注明。

windows服务的创建、安装、调试全过程及引发的后续学习 - lhb62232397  阅读原文»

  前几天做项目的时候需要用到window服务,研究一段时间,算是掌握了最基本的使用方法吧,现总结如下:

  引言:在项目过程中碰到一个问题:需要不断的扫描一个大型数据库表,并获取dataset,以便续的复杂的逻辑处理。如果直接扫描获取并做辑处理,势必会有很大的性能负耗。现在使用windows服务扫描其变化而不获取dataset,只有当windows服务告诉我可以获取dataset时再进行获取,并做逻辑处理,大大提高了其性能。

  windows服务应用程序是一个没有前台界面的应用程序,同时其占用内存资源较小便于长期运行,因此被众多编程者使用,多用于服务器环境下。由于其没有用户界面因此不会产生可视输出,并且可以对其启动和停止进行按需设定,非常方便。

一、创建windows服务:

平台:vs2010

工具:c#

功能实现:向一个txt文件写入当前时间。(完全是学习练习使用,所有没有涉及到特殊的功能)

首先在vs2010中创建一个windows服务工程,默认有一个service1.cs文件,打开此文件,创建一个计时器,每隔1秒钟扫描一次。在计时器的t1_Elapsed中添加编写日志的方法(writelog)。

Onstart控制服务启动;Onstop:控制服务停止。

在OnStart中加入计时器启动的方法,OnStop中加入计时器停止的方法。至此便完成一个简单的Windows服务的创建。

参考代码:

System.Timers.Timer t1 = new System.Timers.Timer();
public Service1()
{
InitializeComponent();
t1.Interval
= 1000;
t1.Elapsed
+= new System.Timers.ElapsedEventHandler(t1_Elapsed);
}

void t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Writelog(DateTime.Now.ToString(
"yyyy-MM-dd hh:mm:ss"));
}
protected override void OnStart(string[] args)
{
t1.Start();
}

protected override void OnStop()
{
t1.Stop();
}

二、安装、发布windows服务:

  将service1.cs的视图设计器打开,右键点击添加按照程序,显现serviceProcessInstaller1和serviceInstaller1两个组件,点击serviceProcessInstaller1的属性,将其改为LocalService,点击serviceInstaller1的属性,可以在serviceName中更改服务的名字,在startType中更改服务的启动方式。最后生成解决方案。

使用InstallUtil.exe工具,安装生成的应用程序。提示:在解决方案生成的项目应用程序的目录下进行安装,可以debug,也可以是release。

在安装过程中可以使用批命令来实现:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil -u FirstService.exe

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil FirstService.exe

其中前面是InstallUtil.exe的存放位置,可以根据不同的版本查找其确切位置。FirstService是应用程序,可以替换为项目生成的应用程序。

注:在安装过程中如果一切顺利当然是幸事,本人的安装足是用了两个下午,最后在一大牛的指导下才安装正确。究其原因,检查你使用的计算机的用户是否对你项目所在位置的盘是否赋予其相应的权利(管理员)。(深受其苦)

三、调试windows服务:

1、将创建的windows服务发布到本地系统中。

2、打开vs2010,在项目源代码中设置断点。

3、点击调试按钮,打开附件到进程对话框,选择所需要进程后点击附加按钮。

4、启动服务即可进行调试。

windows服务成功完成后,原本是想在不同的进程间建立通信,最后经过询问先驱者,本项目的需求是当数据有改变时将其变化保持到另一数据库表即可,完成目标。但是这里勾起了我学习进程间通信的好奇心。

进程间通信方式:

匿名管道:半双工通信方式,数据只能在有亲缘关系的进程间单向流动。通俗来讲:用来在父进程和子进程间传输数据,并且是在本机上使用。

命名管道:相对应匿名管道来说的,单向或双向的,用在服务端和一个或多个客户端进行通讯。一个命名管道的所有实例共享同样的管道名,但是每个实例都有各自的缓存和句柄,作为一个隔离的通道,让客户端-服务器端进行通讯,这些实例允许客户端同时使用相同名字的管道。

信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

消息队列:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点

信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

套接字:日常工作中经常遇到,此次不做介绍。

方式有很多,目前为止只用到过套接字,在时间有限的情况下自己仅选择命名管道进行学习。

命名管道,上面也介绍了很多,它是相对于匿名管道来说的。由于是初次学习,是学习而不是为了完成项目需求,所以本着实现最基本的框架即可的原则来进行下面讲述。

命名管道有两个很重要的类:

NamedPipeClientStream:公开命名管道周围的 System.IO.Stream,该管道既支持同步读写操作,也支持异步读写操作。

NamedPipeServerStream:公开命名管道周围的 System.IO.Stream,该管道既支持同步读写操作,也支持异步读写操作。

从上面的定义也可看出client和server定义相同,因此其通信角色也可互换。同时其定义也正对应着其字面意思。有点拗口,简单来说无非就是定义有名字的管道周围的stream。多余的不说了

参考代码:

Server端:

Thread receiveDataThread = new Thread(new ThreadStart(ReceiveDataFromClient));

private static void ReceiveDataFromClient()
{
while (true)
{
try
{
NamedPipeServerStream pipeServer
= new NamedPipeServerStream("closePipe", PipeDirection.InOut, 2);
pipeServer.WaitForConnec

阅读更多内容

没有评论:

发表评论