I use mysql-native. This driver is suppport vibed's connection pool. On dlang newsgroup mysql-native developer Nick Sabalausky wrote:
"If you're using a connection pool, you shouldn't need to worry about closing the connection. The whole point is that the connections stay open until you need to use one again. When your program ends, then connections will close by themselves."
"You create the pool once (wherever/whenever you want to). Then, every time you want to use the database you obtain a connection by calling MySqlPool.lockConnection."
"Calling 'close' will always close the connection. If you got you connection from the pool, then it will automatically return to the pool when you're no longer using it. No need to do anything special for that."
The question about how pool should be done? I have read about singleton pattern and can't unserstand is it this case.
I wrote next code:
database class:
import std.stdio;
import std.string;
import mysql;
import vibe.d;
import config;
import user;
class Database
{
Config config;
MySqlPool mydb;
Connection connection;
this(Config config)
{
this.config = config;
mydb = new MySqlPool(config.dbhost, config.dbuser, config.dbpassword, config.dbname, config.dbport);
}
void connect()
{
if(connection is null)
{
connection = mydb.lockConnection();
}
scope(exit) connection.close();
}
}
users class/struct:
module user;
import mysql;
import vibe.d;
struct User
{
int id;
string login;
string password;
string usergroup;
}
void getUserByName(string login)
{
User user;
Prepared prepared = prepare(connection, `SELECT id, login, password, usergroup from users WHERE login=?`); // need to get connection accessible here to make request to DB
prepared.setArgs(login);
ResultRange result = prepared.query();
if (result.empty)
logWarn(`user: "%s" do not exists`, login);
else
{
Row row = result.front;
user.id = row[0].coerce!(int);
user.login = row[1].coerce!string;
user.password = row[2].coerce!string;
user.usergroup = row[3].coerce!string;
logInfo(`user: "%s" is exists`, login);
}
}
The problem that I can't understand what is proper way to getting access to connection instance. It seems that it's very stupid ideas to create every new database connection class inside users structure. But how to do it's in better way? To make Connection connection global? Is it's good? Or there is more correct way?
scope(exit) connection.close();
Delete that line. It's closing the connection you just received from the pool before the connect function returns. All you're doing there is opening a connection just to immediately close it again.
Change getUserByName to take a connection as an argument (typically as the first argument). Typically, whatever code needs to call getUserByName should either open a connection, or get a connenction from the pool via lockConnection, and then pass that connection to getUserByName and whatever other DB-related functions it needs to use. Then, after your code is done calling getUserByName (and whatever other DB functions it needs to call), you either just don't worry about the connection anymore and let your vibed fiber finish (if you're using vibed and got the connection from a pool) or you close the connection (if you did NOT get the connection from a vibed pool).
One way to do it is to pass the connection to your functions that need it. So you would refactor your getUserByName() to take connection as an argument.
Another alternative is to use the DAO pattern . Constructor of your DAO class would take the connection as one of the main parameters, and all the methods would use it to do the DB operation.
Related
The controller layer can get the IP using request.getRemoteAddr() and/or request.getHeader("Client-IP") etc.
However, down in the bowels of the service layer, we might want to log some detected or suspected fraudulent activity by the user, along with the IP address of the user. However, the IP is not available to the service layer, nor is the request.
Obviously, every call from every controller method to every single service method could also pass in the IP or the request, but as we have thousands of these calls and lots of chains of them, it is not really practical.
Can anyone think of a better way?
As we are not in charge of instantiation of the services (these just get magically injected), we can't even pass the IP in when each service is created for the current HTTP call.
UPDATE 1
As suggested, tried the MDC route. Unfortunately, this does not seem to work.
in filter:
import org.apache.log4j.MDC
class IpFilters {
def filters = {
all() {
before = {
MDC.put "IP", "1.1.1.1"
println "MDC.put:" + MDC.get("IP")
}
afterView = { Exception e ->
println "MDC.remove:" + MDC.get("IP")
MDC.remove 'IP'
}
}
in service:
import org.apache.log4j.MDC
:
def someMethod() {
String ip = MDC.get("IP")
println("someMethod: IP = $ip")
}
The result is always:
MDC.put:1.1.1.1
MDC.remove:1.1.1.1
someMethod: IP = null
So the service cant access MDC variables put on the thread in the filter, which is a real shame. Possibly the problem is that "someMethod" is actually called by springSecuirty.
Well, it is highly recommended that we should keep the business logic aware of the controller logic. But keeping your situation in mind, you have to do that and absolutely available. In your service method, write this to log the IP address of the current request:
import org.springframework.web.context.request.RequestContextHolder
// ... your code and class
def request = RequestContextHolder.currentRequestAttributes().getRequest()
println request.getRemoteAddr()
Just make sure, you handle the whatever exception thrown from that line when the same service method is invoked from outside a Grails request context like from a Job.
my two pence worth
basically been using above and it works perfectly fine when a request is directed through standard grails practices.
In this scenario, user triggers websockets connection this then is injected into websockets listener using Holders.applicationContext.
The issue arises around are your outside of the web request.
the fix was painful but may come in handy for anyone else in this situation:
private static String userIp
String getIp() {
String i
new Thread({
//to bypass :
// Are you referring to request attributes outside of an actual web request, or processing a
// request outside of the originally receiving thread? If you are actually operating within a web request
// and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet:
// In this case, use RequestContextListener or RequestContextFilter to expose the current request.
def webRequest = RequestContextHolder.getRequestAttributes()
if(!webRequest) {
def servletContext = ServletContextHolder.getServletContext()
def applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)
webRequest = grails.util.GrailsWebMockUtil.bindMockWebRequest(applicationContext)
}
//def request = RequestContextHolder.currentRequestAttributes().request
def request = WebUtils.retrieveGrailsWebRequest().currentRequest
i=request.getRemoteAddr()
if (!i ||i == '127.0.0.1') {
i=request.getHeader("X-Forwarded-For")
}
if (!i ||i == '127.0.0.1') {
i=request.getHeader("Client-IP")
}
if (!i) { i="127.0.0.1"}
this.userIp=i
} as Runnable ).start()
return i
}
Now when calling this some sleep time is required due to it running in as a runnable :
def aa = getIp()
sleep(300)
println "$aa is aa"
println "---- ip ${userIp}"
Also provided alternative way of calling request def request = WebUtils.retrieveGrailsWebRequest().currentRequest in grails 3 the commented out line .request comes up unrecognised in ide (even though it works)
the new Thread({ was still needed since even though it returned ip after getting ip it was attempting to save to a db and some other bizarre issue appeared around
java.lang.RuntimeException: org.springframework.mock.web.MockHttpServletRequest.getServletContext()Ljavax/servlet/ServletContext;
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerBase.handlePojoMethodException(PojoMessageHandlerBase.java:119)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:82)
so the fix to getting hold of request attribute in this scenario is above
for the mock libraries you will require this in build.gradle:
compile 'org.springframework:spring-test:2.5'
So the saga continued - the above did not actually appear to work in my case since basically the request originated by user but when sent to websockets - the session attempting to retrieve Request (ip/session) was not actual real user.
This in the end had to be done a very different way so really steeply off the topic but when this method of attempting ip does not work the only way left is through SessionListeners:
in src/main/groovy/{packageName}
class SessionListener implements HttpSessionListener {
private static List activeUsers = Collections.synchronizedList(new ArrayList())
static Map sessions = [:].asSynchronized()
void sessionCreated (HttpSessionEvent se) {
sessions.put(se.session.id, se.session)
}
void sessionDestroyed (HttpSessionEvent se) {
sessions.remove(se.session.id)
}
}
in grails-app/init/Application.groovy
Closure doWithSpring() {
{ ->
websocketConfig WebSocketConfig
}
}
// this already exists
static void main(String[] args) {
GrailsApp.run(Application, args)
}
in that same init folder:
class WebSocketConfig {
#Bean
public ServletContextInitializer myInitializer() {
return new ServletContextInitializer() {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(SessionListener)
}
}
}
}
Now to get userIP, when the socket initially connects it sends the user's session to sockets. the socket registers that user's session within the websockets usersession details.
when attempting to get the user ip (i have registered the users ip to session.ip on the controller/page hitting the page opening sockets)
def aa = SessionListener.sessions.find{it.key==sessionId}?.value
println "aa $aa.ip"
In my managed bean i need to access a mySql database.
So far i used code like this:
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String username = "user";
String password = "1234";
Connection connection = null;
try {
connection = DriverManager.getConnection(url, username, password);
Now i have to do this in more than one bean, so if i need to change the database credentials, i have to fiddle around in like 10 files.
Is there
a way to store the databaseconnection
a way to define some variables for the whole web project
Thanks in advance
First of all you should understand basic architecture of a Java EE project. It is not a good idea connecting databases in managed beans. It is really bad practice. Please have look my previous answer to understand basic architecture.
Database connections is done in Integration Tier and these classes are called Data Access Objects (DAO).
Create a BaseDao class for static connection properties.
class BaseDao
{
private String url = "jdbc:mysql://localhost:3306/test";
private String username = "user";
private String password = "1234";
private Connection connection;
protected Connection getConnection()
{
connection = DriverManager.getConnection(url, username, password);
return connection;
}
}
and extend base class to its derived classes where database connection is needed and access connection by using BaseDao#getConnection().
Furthermore, it is better to keep database connections in a properties file and inject them into proper classes.
Related Tutorial
Read BalusC tutorial for better understanding DAO tutorial - the data layer
It is generally a good idea to store these kind of values in a .properties file. They can then be accessed via java.util.Properties (http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html)
Here is a good tutorial describing how access these files and their values, I suggest you start with this: http://www.mkyong.com/java/java-properties-file-examples/
(More information: http://en.wikipedia.org/wiki/.properties)
In my IDE, I usually create a new source package /src/main/config and put all my configuration-concerning .properties and .xml files in there. If you do it this way, you need to access it like this from within your jsf application:
String configFilePath = "configuration.properties";
props = new Properties();
InputStream propInStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(configFilePath);
props.load(propInStream);
Or you can simply do this:
How to get properties file from /WEB-INF folder in JSF?
I have a timer task that closes a connection when it's triggered, the problem is that sometimes it is triggered before the connection actually opens, like this:
try {
HttpConnection conn = getMyConnection(); // Asume this returns a valid connection object
// ... At this moment the timer triggers the worker wich closes the connection:
conn.close(); // This is done by the timeTask before conn.getResponseCode()
int mCode = conn.getResponseCode(); // BOOOMMMM!!!! EXPLOTION!!!!
// ... Rest of my code here.
} catch(Throwable e) {
System.out.println("ups..."); // This never gets called... Why?
}
When I try conn.getResponseCode(), an exception is thrown but isn't cought, why?
I get this error: ClientProtocol(HttpProtocolBase).transitionToState(int) line: 484 and a source not found :S.
The connection lives in a different thread, and has its own lifecycle. You are trying to access it from the timer thread in a synchronous way.
To begin with, a connection is a state machine. It starts in the "setup" state, then changes to the "connected" state if some methods are called on it (any method that requires to contact the server), and finally it changes to the "closed" state when the connection has been terminated by either the server or the client. The method getResponseCode is one of those that can cause the connection to transition from the so called "setup" state to the "connected" state, if it wasn't already connected. You are trying to get the response code immediatly without even knowing whether the connection was established or not. You are not even letting the connection time to connect or close itself properly. Even if you could, have a look at what the javadocs say about the close method:
When a connection has been closed, access to any of its methods except this close() will cause an an IOException to be thrown.
If you really need to do something after it has been closed, pass a "listener" object to the connection so that it can call back when the connection has been closed, and pass back the response code (if the connection with the server was ever stablished).
At the heart of Petapoco.cs there is the function OpenShareConnection.
I believe this cannot take advantage of the Connection Pool in SQL Azure.
I am monitoring my connections and the connection count grows above the pool limit.
Anyone has done some improvements?
Here is the OpenShareConnection (from Petapoco open source):
public void OpenSharedConnection()
{
if (_sharedConnectionDepth == 0)
{
//read the connection string from web.config and
//create a new connection
_sqlConnection = _factory.CreateConnection();
_sqlConnection.ConnectionString = _connectionString;
// Wrap this method with a retry policy.
_sqlConnection.Open();
_sqlConnection = OnConnectionOpened(_sqlConnection);
if (KeepConnectionAlive)
_sharedConnectionDepth++; // Make sure you call Dispose
}
_sharedConnectionDepth++;
}
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling
As far as I can see Petapoco is fighting the basic premise behind ADO connection pooling not creating a new SQLConnection(string connectionString) and then performing a .Close() method when the connection is closed.
Not surprising there are nothing but crickets chirping on this 4 yr. 9 month old question.
I'm in a hoo-ha with my boss as I can't shift to using newer technologies until I have proof of some outstanding issues. One of the main concerns is how repositories deal with connections. One of the supposedly largest overheads is connecting and disconnecting to/from the database. If I have a repository where I do the following:
public ContractsControlRepository()
: base(ConfigurationManager.ConnectionStrings["AccountsConnectionString"].ToString()) { }
with the class like so:
public class ContractsControlRepository : DataContext, IContractsControlRepository
with functions like:
public IEnumerable<COContractCostCentre> ListContractCostCentres(int contractID)
{
string query = "SELECT C.ContractID, C.CCCode, MAC.CostCentre, C.Percentage FROM tblCC_Contract_CC C JOIN tblMA_CostCentre MAC ON MAC.CCCode = C.CCCode WHERE C.ContractID = {0}";
return this.ExecuteQuery<COContractCostCentre>(query, contractID);
}
Now if in my controller action called _contractsControlRepository.ListContractCostCentres(2) followed immediately by another call to the repository, does it use the same connection? When does the connection open in the controller? When is it closed?
Cheers
EDIT
I'm using hand-written LINQ as suggested by Steve Sanderson in his ASP.NET MVC book.
EDIT EDIT
To clarify, I'm using LINQ as my ORM, but I'm using raw SQL queries (as shown in the extract above) for querying. For example, here's a controller action:
public ActionResult EditBusiness(string id)
{
Business business = _contractsControlRepository.FetchBusinessByID(id);
return View(business);
}
I'm not opening/closing connections.
Here's a larger, more complete extract of my repo:
public class ContractsControlRepository : DataContext, IContractsControlRepository
{
public ContractsControlRepository()
: base(ConfigurationManager.ConnectionStrings["AccountsConnectionString"].ToString()) { }
public IEnumerable<COContractCostCentre> ListContractCostCentres(int contractID)
{
string query = "SELECT C.ContractID, C.CCCode, MAC.CostCentre, C.Percentage FROM tblCC_Contract_CC C JOIN tblMA_CostCentre MAC ON MAC.CCCode = C.CCCode WHERE C.ContractID = {0}";
return this.ExecuteQuery<COContractCostCentre>(query, contractID);
}
Then ContractsControlRepository is instantiated in my controller and used like _contractsControlRepository.ListContractCostCentres(2). Connections aren't opened manually, DataContext deals with that for me.
Without knowing the details of your ORM and how it connects the SQL database drivers will connection pool. When a connection is closed it is released back to the pool and kept open for X number of seconds (where X is configurable). If another connection is opened and all the parameters match (the server name, the application name, the database name, the authentication details etc.) then any free, but open connections in the pool will get reused instead of opening a brand new connection.
Having not read the book in question I don't know what "manual linq" actually is. If it's manual means you're getting the tables back youself then obviously you're doing the connection open/close. Linq to SQL will use a new connection object when a statement is finally executed at which point connection pooling comes into play - which means a new connection object may not be an actual new connection.