Question

I have 2 separate data connections I need to to handle during the lifecycle of a j2ee application. One has all of its properties known before hand and I configure myBatis as so

    <environment id="development">
        <transactionManager type="JDBC" />
        <dataSource type="JNDI">
            <property name="data_source" value="java:comp/env/jdbc/pooledDS" />
        </dataSource>
    </environment>

This is great. PooledDS refers to my c3p0 configured data source. The second connection will be created with a username/password combo which is determined when a user logs in to the application. I would like to use c3p0 again for that data source and I attempt to configure mybatis.xml as

    <environment id="user">
        <transactionManager type="JDBC" />
        <dataSource type="JNDI">
            <property name="data_source" value="java:comp/env/jdbc/pooledDS2" />
        </dataSource>
    </environment>

My corresponding resource entry in my Tomcat's context.xml is

   <Resource name="jdbc/pooledDS2" auth="Container" 
         description="DB Connection for Users" 
         driverClass="oracle.jdbc.driver.OracleDriver"
         maxPoolSize="100" minPoolSize="10" acquireIncrement="1" 
         factory="org.apache.naming.factory.BeanFactory"
         maxIdleTime="850"  
         type="com.mchange.v2.c3p0.ComboPooledDataSource" 
         jdbcUrl="jdbc:oracle:thin:@localhost:1521:orcl4" /> 

You see, I leave the user and password attributes blank because I do not know them. When I know the user for whom I need a connection I try the following:

        Reader reader = Resources.getResourceAsReader(RESOURCE);
        Properties userProps = new Properties();
        userProps.setProperty("user", loginName);
        userProps.setProperty("username", loginName);
        userProps.setProperty("password", password);
        sqlMapperUser = new SqlSessionFactoryBuilder().build(reader, "user", userProps);

You see, I try to pass in the username and password as a Property object when I get my SqlSessionFactory. When I look at my log messages in tomcat for c3p0 I see that the c3p0 properties are empty and apparently it never heard from myBatis what the username and password are so it cannot make a connection. I know I am using the correct "user" environment, it is just how do I properly set the username and password for this connection? Thanks for your help.

Was it helpful?

Solution

Ok I figured out everything I need to do so let me share.

I found this tidbit somewhere or another on the mybatis google mailing list:

import java.beans.PropertyVetoException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.datasource.DataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0DataSourceFactory implements DataSourceFactory { 

    private ComboPooledDataSource dataSource = null; 

    public C3P0DataSourceFactory () { 
    } 

    public void setProperties(Properties properties) { 
        this.dataSource = new ComboPooledDataSource(); 
        this.dataSource.setPassword(properties.getProperty("password"));
        this.dataSource.setJdbcUrl(properties.getProperty("url"));
        try {
            this.dataSource.setDriverClass(properties.getProperty("driver"));
        } catch (PropertyVetoException e) {
        }
    } 

    public DataSource getDataSource() { 
        return (this.dataSource); 
    }

Much too my chagrin though, I can not pass in my own properties as I was trying to do. The only properties which appear in the above setProperties method are those which are defined in the mybatis.xml file, how disappointing.

Then we adjust the call to build as follows:

            Reader reader = Resources.getResourceAsReader(RESOURCE);
        Properties userProps = new Properties();
        sqlMapperUser = new SqlSessionFactoryBuilder().build(reader, "user");
        ComboPooledDataSource ds = (ComboPooledDataSource) sqlMapperUser.getConfiguration().getEnvironment().getDataSource();
        ds.setUser(loginName);

How disappointing! I have to know what kind of DataSource I am using. That sort of reduces some of the real meat of MyBatis. Anyway, here I know which username is to be selected so I set the User property of that particular c3p0 datasource and now I can open up sessions with mybatis as usual.

Finally, what does the "user" environment look like? How about this?

        <environment id="user">
        <transactionManager type="JDBC" />
        <dataSource type="C3P0DataSourceFactory">
            <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
            <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl4" />
            <property name="password" value="snotty" />             
        </dataSource>

    </environment>

So here I have left out the user property to be set dynamically like I just demonstrated. That is it, MyBatis integrated with c3p0. I think this demonstrates a weakness of MyBatis that you have to delve deep down into the SqlSessionFactory object. But then again, if I choose a framework I am unrealistically expecting magic. And with MyBatis I do not get magic. Otherwise, there are other choices which can be made to handle persistance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top