Scala 之 mysql 数据库连接池

24 篇文章 0 订阅

转子:http://blog.csdn.net/weinierzui/article/details/72867329


看到有大神用sparkstreaming里面的MongoDB 创建的工具类,好像很厉害,但是现在还不太懂。

存在问题:无法将spark产生的dataframe数据用这种方式,存放到数据库中。????????????


数据库操作方法:
jdbcUtile  类
dataframe.write.jdbc

数据库连接池:
MongoDB
自己写连接池




一下工具类,只要修改数据库连接参数就可使用,本人使用的是properties配置文件读取的稍有出入,代码奉上:
var prd:PreparedStatement = null
  val props = getProperties()
 private var current_num = 0      //当前连接池已产生的连接数
  private val max_connection = props.getProperty("orc.max_connection")     //最大连接数
  private val connection_num = props.getProperty("orc.init_connection_num") //初始化产生连接数
  private val pools = new LinkedList[Connection]()   //连接池
  private val driver = props.getProperty("driver")
  private val url = props.getProperty("url")
  private  val user = props.getProperty("user")
  private val pwd = props.getProperty("password")
获取配置文件的工具方法:
def getProperties(): Properties ={
    val props = new Properties()
    val in=this.getClass.getClassLoader.getResourceAsStream("dbconfig.properties")
    props.load(in)
    props
  }

scala数据库工具类

scala的数据库连接池,基于mysql

复制代码
import java.util.concurrent.ConcurrentHashMap
import com.jolbox.bonecp.{ BoneCPConfig, BoneCP }
import java.util.ResourceBundle
import java.util.LinkedList
import java.sql.DriverManager
import java.sql.Connection

/**
 * 数据库连接池工具类
 * 语言:scala
 * 时间:2016-07-09
 */
object DBConnectionPool {
  private val reader = ResourceBundle.getBundle("connection")
  private val max_connection = reader.getString("jeecg.max_connection") //连接池总数
  private val connection_num = reader.getString("jeecg.connection_num") //产生连接数
  private var current_num = 0 //当前连接池已产生的连接数
  private val pools = new LinkedList[Connection]() //连接池
  private val driver = reader.getString("jeecg.driver")
  private val url = reader.getString("jeecg.url")
  private val username = reader.getString("jeecg.username")
  private val password = reader.getString("jeecg.password")
 /**
  * 加载驱动
  */
  private def before() {
    if (current_num > max_connection.toInt && pools.isEmpty()) {
      print("busyness")
      Thread.sleep(2000)
      before()
    } else {
      Class.forName(driver)
    }
  }
  /**
   * 获得连接
   */
  private def initConn(): Connection = {
    val conn = DriverManager.getConnection(url, username, password)
    conn
  }
  /**
   * 初始化连接池
   */
  private def initConnectionPool(): LinkedList[Connection] = {
    AnyRef.synchronized({
      if (pools.isEmpty()) {
        before()
        for (i <- 1 to connection_num.toInt) {
          pools.push(initConn())
          current_num += 1
        }
      }
      pools
    })
  }
  /**
   * 获得连接
   */
  def getConn():Connection={
     initConnectionPool()
     pools.poll()
  }
  /**
   * 释放连接
   */
  def releaseCon(con:Connection){
    pools.push(con)
  }
  
}
复制代码

配置文件

复制代码
#数据库连接池配置文件
jeecg.driver=org.gjt.mm.mysql.Driver
jeecg.url=jdbc\:mysql\://0.0.0.0\:3306/jeecg?useUnicode=true&characterEncoding=utf-8
jeecg.username=root
jeecg.password=****
jeecg.max_connection=8
jeecg.connection_num=10
复制代码

dao类

复制代码
import java.sql.ResultSet
import java.sql.PreparedStatement
import java.sql.Connection
import java.sql.Statement
/**
 * 数据操作工具类
 * 语言:scala
 * 时间:2016-07-09
 */
private[org] abstract class BaseDao[T](conn: Connection) {
  /**
   * 插入数据
   * @param sql SQL语句
   * @param params 参数列表
   * @param convert 主键转换方法
   * @return 转换结果
   */
  protected def insert[T](sql: String, params: Array[Any])(convert: ResultSet => T) = {
    val pstmt = conn prepareStatement (sql, Statement.RETURN_GENERATED_KEYS)
    setParameters(pstmt, params)
    pstmt.executeUpdate
    val rs = pstmt.getGeneratedKeys
    rs.next
    convert(rs)
  }

  /**
   * 更新数据
   * @param sql SQL语句
   * @param params 参数列表
   * @return 影响行数
   */
  protected def update(sql: String, params: Array[Any]) = createStatement(sql, params).executeUpdate

  /**
   * 查询对象
   * @param sql SQL语句
   * @param params 参数列表
   * @param convert 结果集转换方法
   * @return 泛型对象
   */
  protected def queryForObject[T](sql: String, params: Array[Any])(convert: ResultSet => T) = {
    val rs = query(sql, params)
    if (rs.next) {
      val result = convert(rs)
      if (rs.next) {
        val ex = new ResultsTooManyException
        throw ex
      } else Some(result)
    } else None
  }

  /**
   * 查询对象列表
   * @param sql SQL语句
   * @param params 参数列表
   * @param convert 结果集转换方法
   * @return 泛型对象列表
   */
  protected def queryForList[T](sql: String, params: Array[Any])(convert: ResultSet => T) = {
    val rs = query(sql, params)
    var results = List[T]()
    while (rs.next) { results = results :+ convert(rs) }
    results
  }

  /**
   * 查询对象映射
   * @param sql SQL语句
   * @param params 参数列表
   * @param convert 结果集转换方法
   * @return 泛型对象映射
   */
  protected def queryForMap[K, V](sql: String, params: Array[Any])(convert: ResultSet => (K, V)) = {
    val rs = query(sql, params)
    var results = Map[K, V]()
    while (rs.next) { results += convert(rs) }
    results
  }

  /**
   * 查询
   * @param sql SQL语句
   * @param params 参数列表
   */
  private def query(sql: String, params: Array[Any]) = createStatement(sql, params).executeQuery

  /**
   * 创建声明
   * @param sql SQL语句
   * @param params 参数列表
   */
  private def createStatement(sql: String, params: Array[Any]) = {
    val pstmt = conn prepareStatement sql
    setParameters(pstmt, params)
    pstmt
  }

  /**
   * 插入参数
   * @param pstmt 预编译声明
   * @param params 参数列表
   */
  private def setParameters(pstmt: PreparedStatement, params: Array[Any]) {
    for (i <- 1 to params.length) { pstmt setObject (i, params(i - 1)) }
  }

}

/**
 * 结果值读取器
 */
object ResultValueGetter {

  /**
   * 查询结果值
   * @param rs 结果集
   * @param getResult 获得单个值结果的方法
   * @return 值
   */
  def getResultValue[T](rs: ResultSet)(getResult: ResultSet => T) = {
    val result = getResult(rs)
    if (rs.wasNull) None else Some(result)
  }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getStringValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getString colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getIntValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getInt colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getLongValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getLong colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getDoubleValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getDouble colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getBooleanValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getBoolean colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colNum 列号
   */
  def getTimestampValue(rs: ResultSet, colNum: Int) = getResultValue(rs) { _ getTimestamp colNum }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getStringValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getString colName }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getIntValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getInt colName }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getLongValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getLong colName }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getDoubleValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getDouble colName }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getBooleanValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getBoolean colName }

  /**
   * 获得字符串结果的值
   * @param rs 结果集
   * @param colName 列名
   */
  def getTimestampValue(rs: ResultSet, colName: String) = getResultValue(rs) { _ getTimestamp colName }

}

/**
 * 结果太多异常
 */
class ResultsTooManyException extends Exception("Returned too many results.") {}


附加两外一篇博文:http://www.thebigdata.cn/JieJueFangAn/30366.html

在Spark Streaming的应用程序中,有时候需要将计算结果保存到数据库中,为了高效这里使用批量插入,结合c3po连接池,说明一下使用方法。

  1. 数据计算完成后,在foreachRDD中批量插入数据,因为是针对每一个partiton的数据操作,所以使用 rdd.foreachPartition,这里是一个批量插入页面PV和UV的操作,代码如下

    //RDD[(String,Int,Int)] 的意思是RDD[(页面名称,UV,PV)]
    data.foreachRDD((rdd:RDD[(String,Int,Int)],time:Time)=>{
       rdd.foreachPartition(data=>{
         //从连接池中获取一个连接
         val conn = MDBManager.getMDBManager(isLocal).getConnection
         conn.setAutoCommit(false)
         val sql = "insert into tableName set pageName=?,uvNum=?,pvNum=?"
         val preparedStatement = conn.prepareStatement(sql)
         data.foreach(r => {
           preparedStatement.setObject(1, r._1)
           preparedStatement.setObject(2, r._2)
           preparedStatement.setObject(3, r._3)
           preparedStatement.addBatch()
         })
       //批量提交,如果数据量大,这里可以分批提交
         preparedStatement.executeBatch()
         conn.commit()
         conn.close()
    })
  2. 这里创建一个单例的MDBManager,并使用c3p0获取连接,代码如下

    class MDBManager(isLocal:Boolean) extends Serializable{            
     private val cpds: ComboPooledDataSource = new ComboPooledDataSource(true);
     private val prop = new Properties()
     private var in:InputStream = _    
     isLocal match{
         case true  => in = getClass().getResourceAsStream("/c3p0.properties");
         case false => in = new FileInputStream(new File(SparkFiles.get("c3p0.properties")))
      }       
     try {
       prop.load(in);
       cpds.setJdbcUrl(prop.getProperty("jdbcUrl").toString());
       cpds.setDriverClass(prop.getProperty("driverClass").toString());
       cpds.setUser(prop.getProperty("user").toString());
       cpds.setPassword(prop.getProperty("password").toString());      cpds.setMaxPoolSize(Integer.valueOf(prop.getProperty("maxPoolSize").toString()));      cpds.setMinPoolSize(Integer.valueOf(prop.getProperty("minPoolSize").toString()));      cpds.setAcquireIncrement(Integer.valueOf(prop.getProperty("acquireIncrement").toString()));      cpds.setInitialPoolSize(Integer.valueOf(prop.getProperty("initialPoolSize").toString()));      cpds.setMaxIdleTime(Integer.valueOf(prop.getProperty("maxIdleTime").toString()));
     } catch {
       case ex: Exception => ex.printStackTrace()
     }
     def getConnection:Connection={  
         try {  
             return cpds.getConnection();  
         } catch { 
           case ex:Exception => ex.printStackTrace()
           null
         }  
     }   
    }
    object MDBManager{  
    var mdbManager:MDBManager=_
    def getMDBManager(isLocal:Boolean):MDBManager={
       synchronized{
           if(mdbManager==null){
               mdbManager = new MDBManager(isLocal)
           }
       }
       mdbManager
     }
    }

    因为本地模式和集群模式的不同获取c3p0.properties配置文件也不一样,代码中分别提供了两种获取配件文件的方式,通过参数isLocal来确定使用哪种方式。

  3. 由于使用的是mysql数据库和c3p0连接池,所以提交应用时需要添加mysql连接的jar包和c3p0的jar包,在Spark-submit中添加参数

    --jars /usr/local/spark1.3/lib/mysql-connector-java-5.1.38-bin.jar,/usr/local/spark1.3/lib/c3p0-0.9.1.2.jar
  4. 提交应用时添加c3p0的配置文件,在Spark-submit中添加参数
    --files /usr/local/spark1.3/conf/c3p0.properties



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值