webForumDet fria alternativet

smart databaskoppling?

23 svar · 784 visningar · startad av Gimbo

GimboMedlem sedan dec. 20001 626 inlägg
#1

jag har detta i en includ fil:

function OpenDb()
	    
        Set Conn = Server.CreateObject("ADODB.Connection")
	Conn.Open "***","'***","***"
end function

'--------------------------------------------------------------------

function closeDB()
  'on error resume next
  
  rs.close
  set rs 		= nothing 
  conn.close
  set conn	 	= nothing
 
end function	
%>

denna fil inkluderara jag längst upp på sidan, det jag undrar är ifall databasen öppnas då inklud filen körs, eller körs den då man kallar på funktionen dvs. call openDb() ??

JosefMedlem sedan mars 20023 561 inlägg
#2

Du måste kalla på funktionen.

JosefMedlem sedan mars 20023 561 inlägg
#3

Sedan tycker jag det är lite dumt att stänga recordset´et i closeDB-funktionen.

GimboMedlem sedan dec. 20001 626 inlägg
#4

alltså databasen öppnas inte förens man kallar på den?
varför är det dumt?

JosefMedlem sedan mars 20023 561 inlägg
#5

Nä, funktionen körs inte förrens du kallar på den.

Varför det är dumt? Det blir ganska oflexibelt. Isåfall borde du öppna recordsetet i OpenDB, vilket du inte gör, och det skulle jag inte rekommendera heller.
Nä, jag skulle stänga recordsetet untanför funktionen istället.

Tänk ifall du inte har något recordset i koden men ändå använder databasen t ex: att du kör ett insert-statement. Då är det onödigt att ha ett recordset. Men om du har din funktion som den är nu måste du ha ett recordset att stänga annars får du ett felmeddelande, o dom gillar man ju inte. ;)

cyprysMedlem sedan dec. 20003 563 inlägg
#6

Den lösningen är det inget fel på förutom att du kan ta bort rs.close och set rs = nothing.

Databasen öppnas inte förrän du kallar på subben nej.

Jag körde själv med denna metod tidigare och hade inget problem med den samt att databasen aldrig är öppen mer än nödvändigt. (Faktiskt så hade jag exakt samma namn på mina subbar som du ;) )

Exempel på varför du skall ta bort rs.close

<!-- #include file=inc.asp -->
Call OpenDb()
  conn.execute("INSERT INTO my_counter (hit) bla bla")
Call CloseDb()

Här skapas ju inget rs och det är ju då onödigt/dumt/fel att försöka stänga det objektet. 
Låt hanteringen av recordset ske utanför din inkluderingsfil.
OveRRidEMedlem sedan feb. 200112 078 inlägg
#7

Jag funderar mest på varför din öppningsmetod är en funktion. Den returnerar ju inget. GÖr den till en sub istället isåfall, om du inte vill att den skall returnera ett connectionobjekt, vilket den ju inte gör i dagsläget.

Personligen avnänder jag de här två metoderna för databasjobb, de funkar bra allround, och man slipper dessutom bry sig om något connection-objekt, det sköter sig självt. Du inkluderar bara filen med de här två, och ropar sedan på execute_sql( sql ).

Function execute_sql(strSql)
	Set objConn = getConn()
	If InStr(1, strSql, "UPDATE", 1) Or InStr(1, strSql, "DELETE", 1) Or InStr(1, strSql, "INSERT", 1) Then
		objConn.execute (strSql), , 128
	Else
		Set execute_sql = objConn.execute(strSql)
	End If
	Set objConn = Nothing
End Function

Function getConn()
	fysPath = server.mappath("data/databas.mdb")
		 
	Set objConn = server.CreateObject("ADODB.Connection")
		objConn.open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & fysPath
	Set getConn = objConn
	Set objConn = Nothing
End Function
'returnera rs
set rs = execute_sql("SELECT * FROM table")

'ej returnera rs
execute_sql("INSERT INTO table (col) VALUES (1)")
PatrikBMedlem sedan mars 20002 836 inlägg
#8

vilket inte är speciellt bra om man kör flera recordset på samma sida. Blir en hel del overhead att öppna och stänga databasen för varje recordset du kör.

Själv använder jag mig av en VB Script Class om jag inte kan installera komponenter på servern.

vb script classen finns med som en bifogad fil och används så här:

<%
Set objDB = new ADOWrapper
	'## -- vilken connection-string som ska anvädnas --
	objDB.ConnectionString = "MyConnectionString"
	'## -- öppna databasen --
	Call objDB.OpenConnection()
	
	'## -- skapa en 2-dimensionell array --
	varyArray = objDB.GetDbRows("MyQueryToRun")
	
	'## -- skapa ett recordset --
	Set rst = objDB.GetConnection().Execute("MyQueryToRun")
	
	Set rst = Nothing
	
	'## -- skapa ett adodb.recordset utan paging --
	Set rst = objDB.GetAdoRecordset("MyQueryToRun")
	
		rst.Close
	Set rst = Nothing
	
	'## -- skapa ett adodb.recordset med paging --
	Set rst = objDB.GetPagingRecordset("MyQueryToRun", pageToView, pageSize)
	
		rst.Close
	Set rst = Nothing
	
	'## -- för att uppdatera, ta bort lägga till nya records --
	Call objDB.ExecuteNonQuery("MyUpdateDeleteOrInsertQueryToRun")
	
	'## -- stäng databasen --
	Call objDB.CloseConnection()
Set objDB = Nothing
%>
<!--#include virtual="/my_class_folder/clsADOWrapper.asp"-->

finns lite andra metoder för att hämta OpenSchema, adodb.recordset i uppdaterings-"läge"

cya,
PatrikB

OveRRidEMedlem sedan feb. 200112 078 inlägg
#9

vilket inte är speciellt bra om man kör flera recordset på samma sida. Blir en hel del overhead att öppna och stänga databasen för varje recordset du kör.

Sant. Men om man inte gör det, så. ;)

Jag brukar köra med en liknande 'wrapper' som den ovan, som du skrivit någon gång, eller någon som är anpassad för just den typen av app man jobbar med.

PatrikBMedlem sedan mars 20002 836 inlägg
#10

Den wrappern som jag skrev tidigare är en helt annan. Har skrivit om denna som funkar betydligt bättre :e

cya,
PatrikB

OveRRidEMedlem sedan feb. 200112 078 inlägg
#11

PatrikB skrev:

Den wrappern som jag skrev tidigare är en helt annan. Har skrivit om denna som funkar betydligt bättre :e

cya,
PatrikB

Ja, den är imponerande. :)

Om man nu inte är allergisk mot att använda klasser, vilket många kan vara i det här forumet. ;)

JosefMedlem sedan mars 20023 561 inlägg
#12

cyprys skrev:

Den lösningen är det inget fel på förutom att du kan ta bort rs.close och set rs = nothing.

Det var ju det jag menade. ;)

PatrikBMedlem sedan mars 20002 836 inlägg
#13

Thx OveRRide.

OveRRidE skrev:

Om man nu inte är allergisk mot att använda klasser, vilket många kan vara i det här forumet. ;)

Hur kan man vara det ... ;)

/PatrikB

OveRRidEMedlem sedan feb. 200112 078 inlägg
#14

En liten ändring bara, PatrikB. Jag upptäckte att villkoret för att kolla ifall det är mysql eller mssql/access var felvänt. Om det inte finns något i parametern, skall Access användas, inte tvärtom. Dessutom går det inte att lämna parametern tom i det fallet (vilket gör att parametern måste vara minst ett mellanslag ( " " ), så en trim() på rätt ställe gör väl susen. (Hur var det nu igen med optional parameters i VBScript? ;))

Kodförslag:

	Public Function GetLastInsertID(ByVal sTblName) ' As Integer
		Dim queryLastID	' As String
		Dim rstLastID	' As Recordset
		
		QueryCount = QueryCount + 1
		Select Case Len("" & [b]trim([/b]sTblName[b])[/b])
			Case 0
				'## -- MS-SQL Server and Access way --
				queryLastID = "SELECT @@IDENTITY" 
			Case Else
				'## -- my-sql way --
				queryLastID = "SELECT last_insert_id() FROM " & sTblName
		End Select
		
		Set rstLastID = GetConnection().Execute(queryLastID)
			GetLastInsertID = CLng(rstLastID(0))
			rstLastID.Close
		Set rstLastID = Nothing
	End Function
Engine^Medlem sedan dec. 20003 887 inlägg
#15

Inte för att vara petig men

Select Case Len("" & trim(sTblNam))

"" gör väl ändå ingen skillnad...

PatrikB jag har en liten följdfråga, om än i fel forum, men är det möjligen så, att du gjort en liknande klass för .NET? Jag håller på och fifflar med en liknande klass, men jag känner mig som Bambi... :l

GladhMedlem sedan maj 20012 812 inlägg
#16

vilket inte är speciellt bra om man kör flera recordset på samma sida. Blir en hel del overhead att öppna och stänga databasen för varje recordset du kör.

Jag skulle säga precis tvätom. Öppna din databas koppling så sent som möjligt och stäng den så sent som möjligt. Alltså är de 2 funktionern alldeles utmärkta.

Anledningen är att du inte öppnar och stänger din databaskoppling varje gång utan att du istället hämtar och lämnar en öppen koppling från kopplingspoolen (konstigt ord).

Så här fungerar det. Man skall (alltid) ha något som kallas för connectionpooling, vilket betyder att du har ett antal öppna kopplingar till din databas (default brukar vara 5) som ligger och väntar på att användas. När du sedan öppnar en databaskoppling så hämtas en ledig koppling från poolen och du slipper overheaden att öppna databasen.

Detta betyder också att man skall lämna tillbaks den så fort man är färdig med den så att någon annan kan använda den. Eftersom du (oftas) bara har 5 så betyder det att om det kommer en 6 person och vill ha en koppling samtidigt som de 5 andra är upptagna så måste en ny koppling skapas till databasen (det tar tid).

Nu kan man tycka det spelar ingen roll om jag ändå bara gör så här:

1. Öppna databaskoppling
2. hämta data
3. skriv ut data
4. hämta ny data
5. skriv ut data
6. stäng koppling

istället för
1. Öppna databaskoppling
2. hämta data
3. skriv ut data
4. stäng koppling

5. Öppna koppling
6. hämta ny data
7. skriv ut data
8. stäng koppling

Problemet är att det inte är du som bestämmer när din kod skall köras ut det är trådhanteringen i IIS, vilket gör att i det översta exemplet mellan punkt 3 och 4, så kanske den tråd som exekverar din sida lämnar ifrån sig exekveringen till en annan tråd. Du har då en öppen databaskoppling som du inte gör något med. Vilket betyder att du har färre lediga kopplingar i din pool. Jämfört med om tråden bryts mellan 4 och 5 i exemplet nedan, då har man redan lämnat tillbaka kopplingen till poolen.

ovanstående exempel är extremfallet eftersom trådexkveringen kanske bryts mellan 5 och 6 i nedre exemplet och då är ju kopplingen ändå upptagen. Men framför allt så skall man släppa sin databaskoppling så fort man inte gör något med den, speciellt om man sysslar med annan tung processkod (typ loopar och andra beräkningar) som inte har med databasen att göra.

Det är bland annat därför som GetRows() är bra för siter med många besökare, eftersom du då kan lämna tillbaka databaskopplingen innan du loopar igenom din array med data.

- M

GladhMedlem sedan maj 20012 812 inlägg
#17

PatrikB jag har en liten följdfråga, om än i fel forum, men är det möjligen så, att du gjort en liknande klass för .NET? Jag håller på och fifflar med en liknande klass, men jag känner mig som Bambi...

Ms har gjort en SQL Helper "class" som du kan ladda ner gratis från MS sida: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/daab-rm.asp

Finns även en PPT slide här om SQLHelper: http://www.microsoft.com/israel/msdn/downloads/netsa/appblocks.ppt

- M

Engine^Medlem sedan dec. 20003 887 inlägg
#18

Gladh, man tackar. :)

Det var, så gott som, precis det jag var ute efter.

OveRRidEMedlem sedan feb. 200112 078 inlägg
#19

Engine^ skrev:

Inte för att vara petig men

Select Case Len("" & trim(sTblNam))

"" gör väl ändå ingen skillnad...

Nej, men den där konkateneringen med "" ser till att ett eventuellt NULL-värde i inparametern blir en sträng istället, för att undvika ett felmeddelande.

Engine^Medlem sedan dec. 20003 887 inlägg
#20

OverRRidE skrev:

Nej, men den där konkateneringen med "" ser till att ett eventuellt NULL-värde i inparametern blir en sträng istället, för att undvika ett felmeddelande.

Ok, så långt tänkte jag givetvis inte. Jag brukar testa mot null, vilket antagligen kan vara lite långsammare :)

139 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
136 ms — hämta tråd, inlägg och bilagor (db)