135 | | The {{{Environment}}} method {{{get_db_cnx()}}} returns a connection from the pool of connections. This connection needs to be returned, and Trac is written so that the return will happen automatically by the garbage collector if the code is written to follow a simple rule. When the garbage collector determines the pooled database connection is no longer being used, its `__del__` method will return the pooled connection to the pool for reuse. If you have set a lexical variable in the function's body to the pooled connection, this typically occurs when the function is returning. In the example above of {{{myFunc}}} it occurs at the return statement since {{{db}}} is a variable local to {{{myFunc}}} |
| 135 | Trac used to operate the following way: |
| 136 | The {{{Environment}}} method {{{get_db_cnx()}}} returns a connection from the pool of connections. This connection needs to be returned, and Trac is written so that the return will happen automatically by the garbage collector if the code is written to follow a simple rule. When the garbage collector determines the pooled database connection is no longer being used, its `__del__` method will return the pooled connection to the pool for reuse. If you have set a lexical variable in the function's body to the pooled connection, this typically occurs when the function is returning. In the example above of {{{myFunc}}} it occurs at the return statement since {{{db}}} is a variable local to {{{myFunc}}} |
| 137 | |
| 138 | With the context managers introduced in Trac 0.13, we're able to return this Connection to the pool in a much more robust and direct way: |
| 139 | When the control flow exits a context manager (either `Environment.db_query` or `Environment.db_transaction`), and if that context manager is the "outermost" one in case multiple contexts where nested, then the `Connection` is immediately returned to the pool, regardless of the behavior of the garbage collector. |
| 140 | |
| 141 | This means that even if a variable still contains a reference to the `Connection`, it won't be possible to use it outside of the context: |
| 142 | {{{#!pycon |
| 143 | >>> from trac.env import open_environment |
| 144 | >>> env = open_environment('...-trac') |
| 145 | >>> with env.db_query as db: |
| 146 | ... print db("SELECT count(*) FROM wiki") |
| 147 | ... |
| 148 | [(563,)] |
| 149 | >>> db |
| 150 | <trac.db.util.ConnectionWrapper object at 0x026146E8> |
| 151 | >>> print db("SELECT count(*) FROM wiki") |
| 152 | Traceback (most recent call last): |
| 153 | File "<stdin>", line 1, in <module> |
| 154 | File "trac\db\util.py", line 123, in __call__ |
| 155 | cursor = self.cnx.cursor() |
| 156 | File "trac\db\util.py", line 108, in __getattr__ |
| 157 | return getattr(self.cnx, name) |
| 158 | AttributeError: 'NoneType' object has no attribute 'cursor' |
| 159 | }}} |
| 160 | |
| 161 | ... which is a good thing! |
| 162 | |