How to configure two database connection in Lift?

183 views
Skip to first unread message

Neil.Lv

unread,
Dec 6, 2009, 12:47:37 AM12/6/09
to Lift
Hi all,

I want to use two databases, but i don't know how to configure it.

Does anybody know that how to configure two database connection in
Lift?


1:
I add two ConnectionIdentifier in the Boot.class
###
object OneDB extends ConnectionIdentifier {

def jndiName = "one"

}

object TwoDB extends ConnectionIdentifier {

def jndiName = "two"

}
###

2: In the User model

How can i write the code in the method,
###
override def dbCalculateConnectionIdentifier = {
Two
}
###

Thanks for any suggestion!

Cheers,
Neil

Neil.Lv

unread,
Dec 6, 2009, 1:38:17 AM12/6/09
to Lift


Btw, there is the error message when the server is started.
###
scala.MatchError: ConnectionIdentifier(lift)
###

Alex Boisvert

unread,
Dec 6, 2009, 2:00:34 AM12/6/09
to lif...@googlegroups.com
I haven't used multiple connections myself, but I think you have two issues,

1) The default connection identifier is "lift" so you have to define a connection with that name otherwise you'll have to override all Mapper objects to use a different connection.

2) Your dbCalculateConnectionIdentifier method should look like,

override def dbCalculateConnectionIdentifier = {
   case _ => Two
}

meaning, regarless of the mapped object's value, use connection "Two".

and if you always use the same connection for all objects of a given mapper (i.e., you're not sharding) then you can alternatively override the MetaMapper object's dbDefaultConnectionIdentifier method.

Hope this helps,
alex

--

You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.



Neil.Lv

unread,
Dec 6, 2009, 2:02:22 AM12/6/09
to Lift

The two databases that have different structure of the tables, such
as two applications databases.

Cheers,
Neil

Neil.Lv

unread,
Dec 6, 2009, 3:00:49 AM12/6/09
to Lift
In the Boot.scala
###
class Boot {
def boot {
if (!DB.jndiJdbcConnAvailable_?)
DB.defineConnectionManager(DefaultConnectionIdentifier,
DBVendor)
...
}
}

object WahDB extends ConnectionIdentifier {
def jndiName = "one"
}
object WahereDB extends ConnectionIdentifier {
def jndiName = "two"
}

object DBVendor extends ConnectionManager {
...
private def createOne(name: ConnectionIdentifier): Box[Connection] =
try {
val dbUrl1: String = Props.get("db.url1") openOr
"jdbc:derby:lift_example;create=true"

val dbUrl2: String = Props.get("db.url2") openOr
"jdbc:derby:lift_example;create=true"

var dbUrl: String = dbUrl1

try{
name match {
case One => {
dbUrl = dbUrl1
}
case Two => {
dbUrl = dbUrl2
}
case lift => {
dbUrl = dbUrl1
}
}
} catch {
case e : Exception => e.printStackTrace; Empty
}
...
}
...

}

In the every models:
class User extends MegaProtoUser[User] {
def getSingleton = User // what's the "meta" server

...

override def dbCalculateConnectionIdentifier = { //
################## dbCalculateConnectionIdentifier
case _ => One
}
}

class Blog extends LongKeyedMapper[Item] with IdPK {
def getSingleton = Blog // what's the "meta" server

...

override def dbCalculateConnectionIdentifier = { //
################## dbCalculateConnectionIdentifier
case _ => Two
}
}
###

I add the "override def dbCalculateConnectionIdentifier" method in
every models

But everytime it uses the database One, never uses the database Two.

Thanks very much!

Cheers,
Neil

Neil.Lv

unread,
Dec 6, 2009, 5:17:03 AM12/6/09
to Lift

Here is the db url,

db.url1=jdbc:mysql://localhost:3306/blog1
db.url2=jdbc:mysql://localhost:3306/blog2

Cheers,
Neil

Tim Nelson

unread,
Dec 6, 2009, 6:54:06 AM12/6/09
to lif...@googlegroups.com
Hi,

This line configures the database connections:

DB.defineConnectionManager(DefaultConnectionIdentifier,
DBVendor)

This is using only the DefaultConnectionIdentifier, which you don't
want to use. You want to change this to use your 2 defined
identifiers. Ie:

DB.defineConnectionManager(OneDB, DBVendor)
DB.defineConnectionManager(TwoDB, DBVendor)

Tim

Neil.Lv

unread,
Dec 6, 2009, 7:01:08 AM12/6/09
to Lift

If i remove the DB.defineConnectionManager
(DefaultConnectionIdentifier, DBVendor)

This error message occurs.
###
java.lang.NullPointerException: Looking for Connection Identifier
ConnectionIden
tifier(lift) but failed to find either a JNDI data source with the
name lift or
a lift connection manager with the correct name
###

Cheers,
Neil


On Dec 6, 7:54 pm, Tim Nelson <tnell...@gmail.com> wrote:
> Hi,
>
> This line configures the database connections:
>
> DB.defineConnectionManager(DefaultConnectionIdentifier,
> DBVendor)
>
> This is using only the DefaultConnectionIdentifier, which you don't
> want to use. You want to change this to use your 2 defined
> identifiers. Ie:
>
> DB.defineConnectionManager(OneDB, DBVendor)
> DB.defineConnectionManager(TwoDB, DBVendor)
>
> Tim
>

Neil.Lv

unread,
Dec 6, 2009, 7:04:47 AM12/6/09
to Lift

I don't understand the jndiName whether the jndiName is whatever
string that i can specify ?

###
object OneDB extends ConnectionIdentifier {
def jndiName = "one"
}
###

Cheers,
Neil

On Dec 6, 7:54 pm, Tim Nelson <tnell...@gmail.com> wrote:
> Hi,
>
> This line configures the database connections:
>
> DB.defineConnectionManager(DefaultConnectionIdentifier,
> DBVendor)
>
> This is using only the DefaultConnectionIdentifier, which you don't
> want to use. You want to change this to use your 2 defined
> identifiers. Ie:
>
> DB.defineConnectionManager(OneDB, DBVendor)
> DB.defineConnectionManager(TwoDB, DBVendor)
>
> Tim
>

Tim Nelson

unread,
Dec 6, 2009, 7:28:43 AM12/6/09
to lif...@googlegroups.com
I think there might be a problem with the way you are specifying which
db to use in your mapper classes. Here's the relevant text from the
The Lift Book:

dbSelect... is used to find an instance by primary key, and takes a
partial function (typically a match clause) to determine which
connection to use.

dbCalculate... is used when a new instance is created to decide where
to store the new instance.

Those 2 methods are used for sharding. Are you sharding? If not I
think you just want to override dbDefaultConnectionIdentifier

Tim

Neil.Lv

unread,
Dec 6, 2009, 7:46:39 AM12/6/09
to Lift

Yeah, i don't want to use sharding, i just want select some
information from another databases,

###
object Blog extends Blog with LongKeyedMetaMapper[Blog ] {
...
override def dbDefaultConnectionIdentifier = OneDB
...
}
###

It doesn't work, maybe the code that i write is wrong ?

Cheers,
Neil



On Dec 6, 8:28 pm, Tim Nelson <tnell...@gmail.com> wrote:
> I think there might be a problem with the way you are specifying which
> db to use in your mapper classes. Here's the relevant text from the
> The Lift Book:
>
> dbSelect... is used to find an instance by primary key, and takes a
> partial function (typically a match clause) to determine which
> connection to use.
>
> dbCalculate... is used when a new instance is created to decide where
> to store the new instance.
>
> Those 2 methods are used for sharding. Are you sharding? If not I
> think you just want to override dbDefaultConnectionIdentifier
>
> Tim
>

Tim Nelson

unread,
Dec 6, 2009, 9:52:09 AM12/6/09
to lif...@googlegroups.com
I did some more digging and got a sample app to work. You can see the code here:
http://github.com/eltimn/lift_1_1_sample

There are 2 things I had to do. The first is to pass in the DbId when
calling Schemifier;

Schemifier.schemify(true, Log.infoF _, OneDB, User)
Schemifier.schemify(true, Log.infoF _, TwoDB, Dog)

This was the cause of the NPE earlier.

The second thing I did was to create 2 separate DBVendor objects. I
could not get this to work with one that matches on the
ConnectionIdentifier, like the example in The Lift Book. I didn't dig
into why this wasn't working, so it could be the way the code is
written.

DB.defineConnectionManager(OneDB, DBVendor_1)
DB.defineConnectionManager(TwoDB, DBVendor_2)

Tim

Neil.Lv

unread,
Dec 6, 2009, 11:06:58 AM12/6/09
to Lift

Thanks Tim,

I have tried it in my code but it doesn't work yet!

The lift version is: 1.1-M7
Scala Version is: 2.7.7

Cheers,
Neil

Neil.Lv

unread,
Dec 6, 2009, 11:26:46 AM12/6/09
to Lift

It works now, I missing the dbDefaultConnectionIdentifier definition
in the others models.

Thank you very much!

:)

Cheers,
Neil

David Pollak

unread,
Dec 7, 2009, 3:17:37 PM12/7/09
to lif...@googlegroups.com
I've put together some sample code that describes how to access multiple databases from a single Lift app.  It's enclosed.

First, you need to identify different ConnectionIdentifiers for each connection:

package com.liftcode.model

import net.liftweb._
import mapper._

case object CatConnectionIdentifier extends ConnectionIdentifier {
  def jndiName: String = "cat"
}

case object DogConnectionIdentifier extends ConnectionIdentifier {
  def jndiName: String = "dog"
}

Tell your Mapper classes what their default DB is:

package com.liftcode.model

import net.liftweb._
import mapper._


class Cat extends LongKeyedMapper[Cat] with IdPK {
  def getSingleton = Cat

  object name extends MappedString(this, 64)
}

object Cat extends Cat with LongKeyedMetaMapper[Cat] {
  override def dbDefaultConnectionIdentifier = CatConnectionIdentifier
}

class Dog extends LongKeyedMapper[Dog] with IdPK {
  def getSingleton = Dog
 
  object name extends MappedString(this, 64)
}

object Dog extends Dog with LongKeyedMetaMapper[Dog] {
  override def dbDefaultConnectionIdentifier = DogConnectionIdentifier
}


You need to hook the ConnectionIdentifiers up to the actual databases... in Boot:

    DB.defineConnectionManager(DefaultConnectionIdentifier,
                               new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
                                                    Props.get("db.url") openOr "jdbc:h2:lift_proto.db",
                                                    Props.get("db.user"), Props.get("db.password")))

    DB.defineConnectionManager(CatConnectionIdentifier,
                               new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
                                                    Props.get("db.url") openOr "jdbc:h2:lift_cat.db",
                                                    Props.get("db.user"), Props.get("db.password")))

    DB.defineConnectionManager(DogConnectionIdentifier,
                               new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
                                                    Props.get("db.url") openOr "jdbc:h2:lift_dog.db",
                                                    Props.get("db.user"), Props.get("db.password")))

And Schemify based on the correct identifier:

    Schemifier.schemify(true, Log.infoF _, DefaultConnectionIdentifier, User)
    Schemifier.schemify(true, Log.infoF _, CatConnectionIdentifier, Cat)
    Schemifier.schemify(true, Log.infoF _, DogConnectionIdentifier, Dog)

And finally make sure that the transactions are wrapped correctly:

S.addAround(DB.buildLoanWrapper(List(DefaultConnectionIdentifier, DogConnectionIdentifier, CatConnectionIdentifier)))


Cats will come from the Cat DB, dogs from the Dog DB.

It's possible to get shardy with this setup as well, but this should suffice.

Thanks,

David


--

You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.





--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Surf the harmonics
twofer.tgz
Reply all
Reply to author
Forward
0 new messages