关于sqlserver临时表的问题,请教高手!
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于sqlserver临时表的问题,请教高手!相关的知识,希望对你有一定的参考价值。
现在在做一个项目,用到的功能是这样的!
每个表都有触发器,在更新,追加的时候,会给记录的登陆用户,登陆机器名这两个字段设定值!这两个值是在触发器中从本地临时表中取到的!
而临时表是在应用程序中创建的,因为sqlserver的本地临时表是根据会话来的,会话结束了,这个临时表就被删除掉了,所以在应用程序中,使用ExcuteNoQuery()创建临时表时(在存储过程中创建也一样 执行EXEC后会话结束),会话就结束了,临时表就被删除了,
这时更新数据库数据库数据,触发触发器触发时根本找不到之前创建的临时表了,所以不能正确设定登陆用户,登陆机器名了!
如果用全局临时表的话,又怕有并发问题,
有没有高手知道有什么设定或是别的解决办法,请指教啊!
谢谢各位了,问题已经解决,特回来跟大家分享下解决方案!
罪魁祸首是 在做临时表时使用了sql参数(SqlParameter),
把参数以拼字符串的形式穿进去,
ExcuteNoQuery()执行完不会结束会话,不会删除临时表!
这是在国外网站找到了提示,才解决了这个问题,希望对以后遇到相同问题的人能有帮助!
回头你补上一万分吧!还不起就等几年你水平够了进我团队打工偿还。(*^__^*) ……
第一:都不用看,你们就把设计概要给理解错了。
以上只是一些较为简单的实现方式。所以更新登录名等信息用触发器根本就是劣质的。
当下普遍用EDM 更新实体的方式,形式较为简洁,基本对更改过的实体进行更新。
如下这个,只是在跨区域跨范围使用。采用了触发器。
USE [EdwinDW]GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRI_CU_CashFlow] ON [dbo].[CashFlow] AFTER UPDATE
AS
BEGIN
UPDATE M
SET M.LoginPC=N.LoginPC,
M.LoginName=N.LoginName
FROM [dbo].[CashFlow] M
INNER JOIN
(
SELECT RID,LoginPC,LoginName FROM [dbo].[CU_RLog] A
INNER JOIN
(
SELECT MAX(ID) AS ID FROM [dbo].[CU_RLog] B GROUP BY RID
) C ON(A.ID=C.ID)
) N ON (convert(binary(16),M.%%physloc%%)=N.RID)
INNER JOIN INSERTED F ON(M.CashNo=F.CashNo)
ENDDECLARE @CashNo nvarchar(50) set @CashNo='C13081200006'
DECLARE @LoginPC nvarchar(50) set @LoginPC='KROOK'
DECLARE @LoginName nvarchar(50) set @LoginName='KROOK'
------------------------------
--定期删除临时表任务
------------------------------
--模拟所谓的临时表
INSERT INTO [dbo].[CU_RLog]
SELECT
convert(binary(16),A.%%physloc%%),GETDATE(),@LoginPC,@LoginName
FROM [dbo].[CashFlow] A
WHERE A.CashNo=@CashNo
--更新操作
UPDATE [dbo].[CashFlow]
SET CashNo=CashNo
WHERE CashNo=@CashNo
--验证判断
SELECT * FROM [dbo].[CashFlow];
以上只是样例,实际都是自己制定主键方式的。
追问谢谢啊!
再顺便问一下!
这个不会有多用户并发问题吗?
并发是个多线程程序都会有的,
而你这个只要保证存储的是最新的信息就可以认为是正确的。
本身你们项目的实现方案已经通盘是个错误了。
一般保证在同一个事务下运行,设置隔离级别基本可以保证原子操作,但是中间有一个触发器,
根本不可能保证是原子操作。
其实最后那个表还有一列是自增标识,从而实现最新版本信息,而没有采用时间。
谢谢!
这是一个ASP.NET 程序 用到了seasar ,不会出现多用户数据混乱吗?
我仔细想了下,还是不适用啊!
你的方法是针对一个表的,我在临时表做完之后,可能会更新很多表,可能再执行很多SQL文。
还有就是还要定期清理模拟临时表的数据,确实麻烦了点。
%%physloc%% 由 文件号 页码 槽号组成,必然是针对各种表的。
写出方式只是让你比对,得出各种方案的优劣。
看几个代码图
Seasar自动连接数据库
object obj = invocation.Proceed();调用我们操作数据库的dao方法
逻辑方法变成了配置模块里最后的实现体。
也就是说,逻辑方法是有能力获取会话边界能力的。关键是找到对应的实现方式。
至于怎么找就是你的事情了!
//执行创建临时表的sql
com.ExecuteNonQuery();
//这里调用了一个更新或追加的sql
---》
string strsql = "select @userid,@userNm into #pro_set";
这里拼接哪个调用更新或追加的sql,使其与该临时表保持在同一个会话当中
com.ExecuteNonQuery();追问
谢谢回答!
首先创建临时表是在共通方法中实现的
用更新或追加的sql是在具体的业务中实现的,把他们合到一起的工作量会很大,这不是个小项目,几百人月。
那我只能建议你们改用实体表了,把这个临时表创建填充的操作改为实体表的插入
然后跟一个自增的版本号,用ExecuteScalar()返回
在要操作的表中新增一个记录版本号的字段,触发时根据这个值在触发器中操作
谢谢!
我在考虑你的方法,但是修改量不小啊!
修改字段的改动就大了!
难道sqlserver 真就解决不了这个问题吗?
你们的数据入口有很多吗?添加一个记录标识的字段应该不会对数据的增删改查有什么影响
除非你有一些地方用了*,降低了程序的扩展性,这样要是改起来确实麻烦
用临时表这个主意~本身限制就很多,要是考虑用全局临时表其实效果跟实体表一样的
还是要记录一个标识来防止并发
所以,这种方法,跟我一开始回答你的那种,你要衡量一下,感觉还是最上面那种改动小一点呵呵
再次感谢
我贴出来几张代码图 你看下
因为是用searasr 负责连接数据库
通过object obj = invocation.Proceed(); 访问我们的数据库操作类,所以传不进去参数!
因为这个项目已经在使用了,现在有个客户要用sqlserver2012 不用现行系统的postgresql 数据库,在postgresql数据库是没有问题的!
sqlserver的临时表,至少在08前是这样的,2012还没有去研究,不清楚这方面是否有改动
不过感觉应该不会有什么改动
我的想法就是,从一种数据库移植到另一种,肯定有很多地方需要改动,以解决兼容问题
即便是尽量符合ANSI标准,也会含有各自的特色,总之以我目前的能力只能帮到这儿了
已经很感谢了!
我也是想知道之后的版本是否有改进或是提供别的方法,属性什么来实现这个功能!
谢谢分享,没想到在vs中参数化竟然会分隔会话
本回答被提问者和网友采纳 参考技术B 那就在EXEC之前做,不再触发器里面做追问谢谢回答!
创建临时表的方法是基类的方法,每个开启事物时,都会去执行的,增删改查是在你自己方法中做的,所以按现在的系统是不可能拿到前面做了。
不知到还有没有更好的方法?
你用before insert试试
按理说before insert应该在你的Exec之前
string strsql = "select @userid,@userNm into #pro_set";
//执行创建临时表的sql
com.ExecuteNonQuery();
//这里调用了一个更新或追加的sql
object obj = invocation.Proceed();
//提交数据库事物
current.Commit();
Delphi的高手请进,请教一个关于窗体创建的问题!
我在一个窗体放了大量的控件并且用了VCLSKIN,因此窗体在第一次SHOW的时候会出现一个从Delphi最原始的风格到所使用的皮肤的渐变的过程,不爽。因此我将窗体的宽高设为0再SHOW再Hide,再还原窗体大小,在SHOW。这个蠢办法是把问题解决了,可各位大侠可有什么更好的方法呢,希望不吝赐教啊!
我已经加入了 加载窗体
可是如何在加载窗体中 实现主窗体的show 而且还悄悄的进行
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SkinCaption, WinSkinStore, WinSkinData, SpTBXControls,
SpTBXItem, TntStdCtrls, StdCtrls, TntMenus, TBXDkPanels, Menus, TB2Item,
TBXSwitcher, TBX, TB2Dock, TB2Toolbar, ComCtrls, ToolWin, ExtCtrls,
Grids, Mask, Buttons;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Label1: TLabel;
ListBox1: TListBox;
ComboBox1: TComboBox;
RadioGroup1: TRadioGroup;
SpeedButton1: TSpeedButton;
MaskEdit1: TMaskEdit;
StringGrid1: TStringGrid;
Image1: TImage;
ScrollBox1: TScrollBox;
ControlBar1: TControlBar;
StaticText1: TStaticText;
ColorBox1: TColorBox;
RichEdit1: TRichEdit;
ListView1: TListView;
ToolBar1: TToolBar;
StatusBar1: TStatusBar;
TBXDockablePanel1: TTBXDockablePanel;
TBXToolbar1: TTBXToolbar;
TBXMultiDock1: TTBXMultiDock;
TBXDock1: TTBXDock;
TBXSwitcher1: TTBXSwitcher;
TBPopupMenu1: TTBPopupMenu;
TBXButton1: TTBXButton;
TntGroupBox1: TTntGroupBox;
TntEdit1: TTntEdit;
TntPopupMenu1: TTntPopupMenu;
TntMemo1: TTntMemo;
TntCheckBox1: TTntCheckBox;
TntListBox1: TTntListBox;
SpTBXToolbar1: TSpTBXToolbar;
SpTBXSpeedButton1: TSpTBXSpeedButton;
SpTBXButton1: TSpTBXButton;
SkinData1: TSkinData;
SkinStore1: TSkinStore;
SkinCaption1: TSkinCaption;
procedure FormCreate(Sender: TObject);
procedure SkinData1AfterSkinForm(Sender: TObject; ahwnd: HWND;
aName: String);
private
Private declarations
public
Public declarations
end;
var
Form1: TForm1;
implementation
$R *.dfm
procedure TForm1.FormCreate(Sender: TObject);
begin
form1.AlphaBlend:=true;
form1.AlphaBlendValue:=0;
end;
procedure TForm1.SkinData1AfterSkinForm(Sender: TObject; ahwnd: HWND;
aName: String);
begin
form1.AlphaBlend:=false;
form1.AlphaBlendValue:=255;
end;
end. 参考技术A 君不见众软件打开的时候都喜欢一个欢迎界面?
加它的理由很简单
1.版权
2.美观
3.暗地里把事情忙完了(加载组件,皮肤等初始化参数) 参考技术B 嘿嘿,仔细考虑了下
你这个还是不错的方法
嘿嘿
以上是关于关于sqlserver临时表的问题,请教高手!的主要内容,如果未能解决你的问题,请参考以下文章