|
19 | 19 | For this, you have to set MinServerThreads = MaxServerThreads in Webware. |
20 | 20 |
|
21 | 21 | For the Python DB-API 2 specification, see: |
22 | | - http://www.python.org/peps/pep-0249.html |
| 22 | + http://www.python.org/peps/pep-0249.html |
23 | 23 | For information on Webware for Python, see: |
24 | | - http://www.webwareforpython.org |
| 24 | + http://www.webwareforpython.org |
25 | 25 |
|
26 | 26 |
|
27 | 27 | Usage: |
28 | 28 |
|
29 | 29 | First you need to set up a generator for your kind of database connections |
30 | 30 | by creating an instance of PersistentDB, passing the following parameters: |
31 | 31 |
|
32 | | - creator: either an arbitrary function returning new DB-API 2 |
33 | | - connection objects or a DB-API 2 compliant database module |
34 | | - maxusage: the maximum number of reuses of a single connection |
35 | | - (the default of 0 or None means unlimited reuse) |
36 | | - Whenever the limit is reached, the connection will be reset. |
37 | | - setsession: an optional list of SQL commands that may serve to |
38 | | - prepare the session, e.g. ["set datestyle to german", ...]. |
39 | | - failures: an optional exception class or a tuple of exception classes |
40 | | - for which the connection failover mechanism shall be applied, |
41 | | - if the default (OperationalError, InternalError) is not adequate |
42 | | - closeable: if this is set to true, then closing connections will |
43 | | - be allowed, but by default this will be silently ignored |
44 | | - threadlocal: an optional class for representing thread-local data |
45 | | - that will be used instead of our Python implementation |
46 | | - (threading.local is faster, but cannot be used in all cases) |
47 | | -
|
48 | | - The creator function or the connect function of the DB-API 2 compliant |
49 | | - database module specified as the creator will receive any additional |
50 | | - parameters such as the host, database, user, password etc. You may |
51 | | - choose some or all of these parameters in your own creator function, |
52 | | - allowing for sophisticated failover and load-balancing mechanisms. |
| 32 | + creator: either an arbitrary function returning new DB-API 2 |
| 33 | + connection objects or a DB-API 2 compliant database module |
| 34 | + maxusage: the maximum number of reuses of a single connection |
| 35 | + (the default of 0 or None means unlimited reuse) |
| 36 | + Whenever the limit is reached, the connection will be reset. |
| 37 | + setsession: an optional list of SQL commands that may serve to |
| 38 | + prepare the session, e.g. ["set datestyle to german", ...]. |
| 39 | + failures: an optional exception class or a tuple of exception classes |
| 40 | + for which the connection failover mechanism shall be applied, |
| 41 | + if the default (OperationalError, InternalError) is not adequate |
| 42 | + closeable: if this is set to true, then closing connections will |
| 43 | + be allowed, but by default this will be silently ignored |
| 44 | + threadlocal: an optional class for representing thread-local data |
| 45 | + that will be used instead of our Python implementation |
| 46 | + (threading.local is faster, but cannot be used in all cases) |
| 47 | +
|
| 48 | + The creator function or the connect function of the DB-API 2 compliant |
| 49 | + database module specified as the creator will receive any additional |
| 50 | + parameters such as the host, database, user, password etc. You may |
| 51 | + choose some or all of these parameters in your own creator function, |
| 52 | + allowing for sophisticated failover and load-balancing mechanisms. |
53 | 53 |
|
54 | 54 | For instance, if you are using pgdb as your DB-API 2 database module and want |
55 | 55 | every connection to your local database 'mydb' to be reused 1000 times: |
56 | 56 |
|
57 | | - import pgdb # import used DB-API 2 module |
58 | | - from DBUtils.PersistentDB import PersistentDB |
59 | | - persist = PersistentDB(pgdb, 1000, database='mydb') |
| 57 | + import pgdb # import used DB-API 2 module |
| 58 | + from DBUtils.PersistentDB import PersistentDB |
| 59 | + persist = PersistentDB(pgdb, 1000, database='mydb') |
60 | 60 |
|
61 | 61 | Once you have set up the generator with these parameters, you can |
62 | 62 | request database connections of that kind: |
63 | 63 |
|
64 | | - db = persist.connection() |
| 64 | + db = persist.connection() |
65 | 65 |
|
66 | 66 | You can use these connections just as if they were ordinary |
67 | 67 | DB-API 2 connections. Actually what you get is the hardened |
|
112 | 112 |
|
113 | 113 |
|
114 | 114 | class PersistentDBError(Exception): |
115 | | - """General PersistentDB error.""" |
| 115 | + """General PersistentDB error.""" |
116 | 116 |
|
117 | 117 | class NotSupportedError(PersistentDBError): |
118 | | - """DB-API module not supported by PersistentDB.""" |
| 118 | + """DB-API module not supported by PersistentDB.""" |
119 | 119 |
|
120 | 120 |
|
121 | 121 | class PersistentDB: |
122 | | - """Generator for persistent DB-API 2 connections. |
123 | | -
|
124 | | - After you have created the connection pool, you can use |
125 | | - connection() to get thread-affine, steady DB-API 2 connections. |
126 | | -
|
127 | | - """ |
128 | | - |
129 | | - version = __version__ |
130 | | - |
131 | | - def __init__(self, creator, |
132 | | - maxusage=None, setsession=None, failures=None, |
133 | | - closeable=False, threadlocal=None, *args, **kwargs): |
134 | | - """Set up the persistent DB-API 2 connection generator. |
135 | | -
|
136 | | - creator: either an arbitrary function returning new DB-API 2 |
137 | | - connection objects or a DB-API 2 compliant database module |
138 | | - maxusage: maximum number of reuses of a single connection |
139 | | - (number of database operations, 0 or None means unlimited) |
140 | | - Whenever the limit is reached, the connection will be reset. |
141 | | - setsession: optional list of SQL commands that may serve to prepare |
142 | | - the session, e.g. ["set datestyle to ...", "set time zone ..."] |
143 | | - failures: an optional exception class or a tuple of exception classes |
144 | | - for which the connection failover mechanism shall be applied, |
145 | | - if the default (OperationalError, InternalError) is not adequate |
146 | | - closeable: if this is set to true, then closing connections will |
147 | | - be allowed, but by default this will be silently ignored |
148 | | - threadlocal: an optional class for representing thread-local data |
149 | | - that will be used instead of our Python implementation |
150 | | - (threading.local is faster, but cannot be used in all cases) |
151 | | - args, kwargs: the parameters that shall be passed to the creator |
152 | | - function or the connection constructor of the DB-API 2 module |
153 | | -
|
154 | | - """ |
155 | | - try: |
156 | | - threadsafety = creator.threadsafety |
157 | | - except AttributeError: |
158 | | - try: |
159 | | - if not callable(creator.connect): |
160 | | - raise AttributeError |
161 | | - except AttributeError: |
162 | | - threadsafety = 1 |
163 | | - else: |
164 | | - threadsafety = 0 |
165 | | - if not threadsafety: |
166 | | - raise NotSupportedError("Database module is not thread-safe.") |
167 | | - self._creator = creator |
168 | | - self._maxusage = maxusage |
169 | | - self._setsession = setsession |
170 | | - self._failures = failures |
171 | | - self._closeable = closeable |
172 | | - self._args, self._kwargs = args, kwargs |
173 | | - self.thread = (threadlocal or ThreadingLocal.local)() |
174 | | - |
175 | | - def steady_connection(self): |
176 | | - """Get a steady, non-persistent DB-API 2 connection.""" |
177 | | - return connect(self._creator, |
178 | | - self._maxusage, self._setsession, |
179 | | - self._failures, self._closeable, |
180 | | - *self._args, **self._kwargs) |
181 | | - |
182 | | - def connection(self, shareable=False): |
183 | | - """Get a steady, persistent DB-API 2 connection. |
184 | | -
|
185 | | - The shareable parameter exists only for compatibility with the |
186 | | - PooledDB connection method. In reality, persistent connections |
187 | | - are of course never shared with other threads. |
188 | | -
|
189 | | - """ |
190 | | - try: |
191 | | - con = self.thread.connection |
192 | | - except AttributeError: |
193 | | - con = self.steady_connection() |
194 | | - if not con.threadsafety(): |
195 | | - raise NotSupportedError("Database module is not thread-safe.") |
196 | | - self.thread.connection = con |
197 | | - return con |
198 | | - |
199 | | - def dedicated_connection(self): |
200 | | - """Alias for connection(shareable=False).""" |
201 | | - return self.connection() |
| 122 | + """Generator for persistent DB-API 2 connections. |
| 123 | +
|
| 124 | + After you have created the connection pool, you can use |
| 125 | + connection() to get thread-affine, steady DB-API 2 connections. |
| 126 | +
|
| 127 | + """ |
| 128 | + |
| 129 | + version = __version__ |
| 130 | + |
| 131 | + def __init__(self, creator, |
| 132 | + maxusage=None, setsession=None, failures=None, |
| 133 | + closeable=False, threadlocal=None, *args, **kwargs): |
| 134 | + """Set up the persistent DB-API 2 connection generator. |
| 135 | +
|
| 136 | + creator: either an arbitrary function returning new DB-API 2 |
| 137 | + connection objects or a DB-API 2 compliant database module |
| 138 | + maxusage: maximum number of reuses of a single connection |
| 139 | + (number of database operations, 0 or None means unlimited) |
| 140 | + Whenever the limit is reached, the connection will be reset. |
| 141 | + setsession: optional list of SQL commands that may serve to prepare |
| 142 | + the session, e.g. ["set datestyle to ...", "set time zone ..."] |
| 143 | + failures: an optional exception class or a tuple of exception classes |
| 144 | + for which the connection failover mechanism shall be applied, |
| 145 | + if the default (OperationalError, InternalError) is not adequate |
| 146 | + closeable: if this is set to true, then closing connections will |
| 147 | + be allowed, but by default this will be silently ignored |
| 148 | + threadlocal: an optional class for representing thread-local data |
| 149 | + that will be used instead of our Python implementation |
| 150 | + (threading.local is faster, but cannot be used in all cases) |
| 151 | + args, kwargs: the parameters that shall be passed to the creator |
| 152 | + function or the connection constructor of the DB-API 2 module |
| 153 | +
|
| 154 | + """ |
| 155 | + try: |
| 156 | + threadsafety = creator.threadsafety |
| 157 | + except AttributeError: |
| 158 | + try: |
| 159 | + if not callable(creator.connect): |
| 160 | + raise AttributeError |
| 161 | + except AttributeError: |
| 162 | + threadsafety = 1 |
| 163 | + else: |
| 164 | + threadsafety = 0 |
| 165 | + if not threadsafety: |
| 166 | + raise NotSupportedError("Database module is not thread-safe.") |
| 167 | + self._creator = creator |
| 168 | + self._maxusage = maxusage |
| 169 | + self._setsession = setsession |
| 170 | + self._failures = failures |
| 171 | + self._closeable = closeable |
| 172 | + self._args, self._kwargs = args, kwargs |
| 173 | + self.thread = (threadlocal or ThreadingLocal.local)() |
| 174 | + |
| 175 | + def steady_connection(self): |
| 176 | + """Get a steady, non-persistent DB-API 2 connection.""" |
| 177 | + return connect(self._creator, |
| 178 | + self._maxusage, self._setsession, |
| 179 | + self._failures, self._closeable, |
| 180 | + *self._args, **self._kwargs) |
| 181 | + |
| 182 | + def connection(self, shareable=False): |
| 183 | + """Get a steady, persistent DB-API 2 connection. |
| 184 | +
|
| 185 | + The shareable parameter exists only for compatibility with the |
| 186 | + PooledDB connection method. In reality, persistent connections |
| 187 | + are of course never shared with other threads. |
| 188 | +
|
| 189 | + """ |
| 190 | + try: |
| 191 | + con = self.thread.connection |
| 192 | + except AttributeError: |
| 193 | + con = self.steady_connection() |
| 194 | + if not con.threadsafety(): |
| 195 | + raise NotSupportedError("Database module is not thread-safe.") |
| 196 | + self.thread.connection = con |
| 197 | + return con |
| 198 | + |
| 199 | + def dedicated_connection(self): |
| 200 | + """Alias for connection(shareable=False).""" |
| 201 | + return self.connection() |
0 commit comments