MyBaits使用实在是烦恼,要建立DAO,还要写XML.嗯也许大多数需求也用不上xml。远不如scala下的各种ORM框架来的简介明了。
先简单列举一下Scala下的ORM框架
- slick:还不错,整合较简单
- quill:整合略麻烦
- squeryl:没用过
- lift-mapper:在liftweb项目中使用
- srom:没用过
这里经过简单的筛选,最终选用了lift-mapper. 为什么要选择他呢,嗯,只有一条原因,lift-mapper不是基于case class的。那不是基于case class就可以超过22个列。超过22个列就不会被db的糟糕设计所束缚。
话不多说,直接开始。
1.首先是常规的springboot开局。大家只要把手头上的启动类更换为scala方式即可.(不更换也可以)。下面给出一个例子
@SpringBootApplication
@ImportResource(Array("classpath:applicationcontext_pro.xml")) //导入xml配置项
@MapperScan(Array("per.brant.project.mapper"))
@ServletComponentScan(basePackages = Array("per.brant.project.filter"))
class MyApplication extends SpringBootServletInitializer{
override def configure(builder: MyApplicationBuilder): SpringApplicationBuilder = {
builder.sources(classOf[MyApplication])
}
}
2.然后我们先常规引入liftweb-mapper。pom.xml新增如下
<dependency>
<groupId>net.liftweb</groupId>
<artifactId>lift-mapper_2.10</artifactId>
<version>2.5</version>
</dependency>
这里我的scala是2.10版本,所以lift-mapper也使用2.10版本
3.引入mapper代码
import net.liftweb.mapper.{IdPK, LongKeyedMapper, LongKeyedMetaMapper, MappedString}
class TestOrm extends LongKeyedMapper[TestOrm]
with IdPK{
def getSingleton = TestOrm
object typeCode extends MappedString(this,256){
override def dbColumnName: String = "type_code"
}
}
object TestOrm extends TestOrm with LongKeyedMetaMapper[TestOrm] {
override def dbTableName = "t_test"
}
这里我只建立了一个t_test的表,里面有两个字断,默认的id:Int和type_code:String
TestOrm.findAll().foreach(println)
这时候大家已经可以在项目需要的地方引入上面的代码来查询数据了。但是很明显,不会成功。因为我们并没有告诉TestOrm如何连接数据库。
4.引入DB配置
//声明一个标准的Vendor
object DBVendor extends StandardDBVendor(
Props.get("db.driver").openOr("com.mysql.jdbc.Driver"),
Props.get("db.url").openOr("jdbc:mysql://127.0.0.1:3306/TestDB?useUnicode=true&characterEncoding=UTF-8&useSSL=true"),
Props.get("db.user") or Full("root"),
Props.get("db.pass") or Full("123456")
)
//绑定它
if (!DB.jndiJdbcConnAvailable_?) {
val vendor=DB.defineConnectionManager(DefaultConnectionIdentifier, DBVendor)
LiftRules.unloadHooks.append(() =>DBVendor.closeAllConnections_!())
}
Schemifier.schemify(true, Schemifier.infoF _,TestOrm)
将上面的代码在spring.run()之后执行,就可以链接成功数据库了。
那我们做到这里是不是就足够了呢。答案当然是:NO。我们还有两个重要的工作,多数据库和数据连接池
6.多数据库。
先建立两个jndi.网上有例子,我就照抄了,方便大家GG
object SalesDB extends ConnectionIdentifier {
def jndiName = "sales"
}
object EmployeeDB extends ConnectionIdentifier {
def jndiName = "employees"
}
然后搞一个新的ConnectionManager
object DBVendorA extends ConnectionManager {
Class.forName("com.mysql.jdbc.Driver")
def newConnection(name : ConnectionIdentifier) = {
try {
name match {
case SalesDB =>
Full(DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/TestDB?useUnicode=true&characterEncoding=UTF-8&useSSL=true",
"root", "123456"))
case EmployeeDB =>
Full(DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/Test?useUnicode=true&characterEncoding=UTF-8&useSSL=true",
"root", "123456"))
case _ => Empty
}
}
catch
{
case e: Exception => e.printStackTrace; Empty
}
}
def releaseConnection(conn: Connection) {
conn.close
}
}
修改一下TestOrm,再新建一个新的Mapper
object TestOrm extends TestOrm with LongKeyedMetaMapper[TestOrm] {
override def dbTableName = "t_test"
override def dbDefaultConnectionIdentifier = SalesDB
}
import net.liftweb.mapper.{IdPK, LongKeyedMapper, LongKeyedMetaMapper, MappedString}
class TestOrmB extends LongKeyedMapper[TestOrmB]
with IdPK{
def getSingleton = TestOrmB
/**
* 字典类型Code
*/
object typeCode extends MappedString(this,256){
override def dbColumnName: String = "type_code"
}
}
object TestOrmB extends TestOrmB with LongKeyedMetaMapper[TestOrmB] {
override def dbTableName = "t_test"
override def dbDefaultConnectionIdentifier = EmployeeDB
}
最后是使用
TestOrm.findAll()
TestOrmB.findAll()
相信大家已经可以自己验证了。
7.最后我们来使用连接池。这里我选用Hikari。其他连接池也一样的,大家可以照搬。
object DBVendorA extends ConnectionManager {
Class.forName("com.mysql.jdbc.Driver")
def newConnection(name : ConnectionIdentifier) = {
try {
name match {
case SalesDB =>
val config = new HikariConfig()
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/TestDB?useUnicode=true&characterEncoding=UTF-8&useSSL=true");
config.setUsername("root")
config.setPassword("123456")
config.setMaximumPoolSize(15);
config.setMinimumIdle(5)
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250")
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.setConnectionTimeout(20 * 1000);
config.setPoolName(SalesDB.jndiName)
val dataSource = new HikariDataSource(config)
Full(dataSource.getConnection)
case EmployeeDB =>
val config = new HikariConfig()
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/Test?useUnicode=true&characterEncoding=UTF-8&useSSL=true");
config.setUsername("root")
config.setPassword("123456")
config.setMaximumPoolSize(15);
config.setMinimumIdle(5)
config.setPoolName(EmployeeDB.jndiName)
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250")
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.setConnectionTimeout(20 * 1000);
val dataSource = new HikariDataSource(config)
Full(dataSource.getConnection)
case _ => Empty
}
}
catch
{
case e: Exception => e.printStackTrace; Empty
}
}
def releaseConnection(conn: Connection) {
conn.close
}
}
是的,就是这么简单。GG上是没有的。因为lift-mapper流行的时候hikari还没有发布,所以当然不会有人这么玩。
8.最后贴一下结果
Total query time : 22 ms
Exec query "SELECT t_test.type_code, t_test.id FROM t_test " : HikariProxyResultSet@2079891174 wrapping com.mysql.cj.jdbc.result.ResultSetImpl@c694775 in 1 ms
Closed Statement in 0 ms
Closed Statement in 0 ms
per.brant.project.mapper.TestOrm={typeCode=aaaa,id=1}
per.brant.project.mapper.TestOrm={typeCode=bbbb,id=2}
Total query time : 2 ms
Exec query "SELECT t_test.type_code, t_test.id FROM t_test " : HikariProxyResultSet@396064611 wrapping com.mysql.cj.jdbc.result.ResultSetImpl@267c3f2d in 1 ms
Closed Statement in 0 ms
Closed Statement in 0 ms
per.brant.project.mapper.TestOrmB={typeCode=FFFFF,id=1}
per.brant.project.mapper.TestOrmB={typeCode=GGGGG,id=2}
总结:
我们成功的在springboot的框架中整合了lift-mapper。并且完成了多数据库和连接池的功能。能够使用任意多列的数据表而不受case class的22列的束缚。且整合方式轻松愉快,侵入性几乎没有。