JDBC操作数据库的三种方式比较
JDBC(java Database Connectivity)java数据库连接,是一种用于执行上sql语句的javaAPI,可以为多种关系型数据库提供统一访问接口。我们项目中经常用到的MySQL、oracle、DB2等关系型数据库均是通过JDBC来访问的,现在主流的ORM框架Hibernate、Mybatis等均是在JDBC的基础上做的进一步封装、优化。一般小型的项目,可以直接用JDBC来访问数据库,简单方便。我在进过几个项目后,总结了三总JDBC的基本用法,对这几种用法做一个总结。
第一种、连接池+ JDBC
连接池通过将已经建立好的连接保存在连接池中,当有请求的时候,直接使接对数据库进行访问,从而节省了创建连接和关闭连接的时间,性能得到了提高,总之一句话,连接池就是为了提升性能。常用的连接池有DBCP、c3p0、DRUID等,原理都一样。下面是实例:
首先创建连接池:
public class ConnDBUtil{
private static final Log logger = LogFactory.getLog(ConnDBUtil.class);
private static Properties JDBCPOP = new PropertiesUtil().getProperties("jdbc.properties");
private static ComboPooledDataSource cpds;
static{
try {
cpds = new ComboPooledDataSource();
cpds.setDriverClass(JDBCPOP.getProperty("driverName"));
cpds.setJdbcUrl(JDBCPOP.getProperty("url"));
cpds.setUser(JDBCPOP.getProperty("user"));
cpds.setPassword(JDBCPOP.getProperty("drowssap"));
cpds.setAcquireIncrement(Integer.parseInt(JDBCPOP.getProperty("acquireIncrement")));
cpds.setInitialPoolSize(Integer.parseInt(JDBCPOP.getProperty("initialPoolSize")));
cpds.setMinPoolSize(Integer.parseInt(JDBCPOP.getProperty("minPoolSize")));
cpds.setMaxPoolSize(Integer.parseInt(JDBCPOP.getProperty("maxPoolSize")));
cpds.setIdleConnectionTestPeriod(Integer.parseInt(JDBCPOP
.getProperty("idleConnectionTestPeriod")));
} catch (PropertyVetoException e) {
logger.error("c3p0连接异常:"+e.getMessage(),e);
}
}
/**
* 获得c3p0连接
* @return Connection
*/
public Connection getConnection(){
Connection conn = null;
try {
conn= cpds.getConnection();
} catch (SQLException e) {
logger.error(e.getMessage(),e);
e.fillInStackTrace();
}
return conn;
}
public void c3p0Static(ComboPooledDataSource cpds){
try {
logger.info("c3p0总连接数:"+cpds.getNumConnections());
logger.info("c3p0正在使用连接数:"+cpds.getNumBusyConnections());
logger.info("c3p0空闲连接数:"+cpds.getNumIdleConnections());
} catch (SQLException e) {
logger.error(e.getMessage(),e);
}
}
接下来获取连接,jdbc操作数据库,以一个简单的查询为例:
public class Dao{
public String queryHtable(String username) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String HTable=null;
try {
String sql="select tab_name FROM table_user "
+ "WHERE USER_NAME='"+username+"'";
conn=ConnDBUtil.getConnection();
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while(rs.next()){
HTable=rs.getString("USE_HTABLE");
}
} catch (SQLException e) {
logger.error(e.getMessage(),e);
e.fillInStackTrace();
}finally{
closeAll(rs, ps, conn);
}
return HTable;
}
//关闭资源
private static void closeAll(ResultSet rs, PreparedStatement ps, Connection conn) {
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
logger.error(e.getMessage(),e);
e.fillInStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
logger.error(e.getMessage(),e);
e.fillInStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
logger.error(e.getMessage(),e);
e.fillInStackTrace();
}
}
}
以上就是一种非常简单的JDBC操作数据库的例子,缺点是代码耦合度非常高。
第二种、ThreadLocal+JDBC
ThreadLocal,线程局部变量,作用非常简单就是为每一个使用该变量的线程提供一个变量值的副本,这样,每一个线程都可以独立改变自己的副本而不受其他线程的影响,也不会和其他线程副本冲突,从而提高线程安全性,也就是说,每一个线程完全拥有该变量。从源码我们可以看到ThreadLocal是如何维护线程变量副本的,思路很简单,ThreadLocal类中存在一个Map,Map中存储的就是变量副本。
public class GetConnectionType {
public static Connection getConnection() throws SQLException, ClassNotFoundException {
String url = "jdbc:mysql://localhost:3306/test";
String driver = "com.mysql.jdbc.Driver";
String username = "root";
String password = "123456";
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
}
}
public class GetConnection {
private static ThreadLocal<Connection> local = new ThreadLocal<>();
//获取连接
public static Connection getConnection() throws ClassNotFoundException, SQLException {
Connection conn = local.get();
if (conn == null) {
conn = GetConnectionType.getConnection();
conn.setAutoCommit(false);
local.set(conn);
}
return conn;
}
//提交事务
public static void commit() {
try {
if (local.get() != null) {
local.get().commit();
local.get().close();
local.set(null);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚
public static void rollback() {
try {
if (local.get() != null) {
local.get().rollback();
local.get().close();
local.set(null);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public List<Bookinfo> getAllBookinfo() throws SQLException, ClassNotFoundException {
List listBookinfo = new ArrayList();
String sql = "select * from bookinfo order by id asc";
Connection conn = GetConnection.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int idDB = rs.getInt("id");
String booknameDB = rs.getString("bookname");
double bookpriceDB = rs.getDouble("bookprice");
Bookinfo bookinfo = new Bookinfo();
bookinfo.setId(idDB);
bookinfo.setBookname(booknameDB);
bookinfo.setBookprice(bookpriceDB);
listBookinfo.add(bookinfo);
}
rs.close();
ps.close();
return listBookinfo;
}
第三种、通过反射连接JDBC
什么是反射?反射就是对于任何一个类,,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够任意调用它的任何方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。(来自:百度百科)。代码如下:
public class ConnUtil {
private static Log logger = LogFactory.getLog(ConnUtil.class);
private static String sqlDriver;
private static String url;
private static String username;
private static String password;
private static Properties JDBCP = new PropertiesUtil().getProperties("jdbc.properties");
static{
try {
sqlDriver=JDBCP.getProperty("driverName");
url=JDBCP.getProperty("url");
username=JDBCP.getProperty("user");
password=JDBCP.getProperty("drowssap");
Class.forName(sqlDriver);
} catch (ClassNotFoundException e) {
logger.error("mysql注册驱动出错:"+e.getMessage(),e);
}
}
/**
* 获取数据库连接
* @return Connection
*/
public static Connection getConn(){
Connection connection=null;
try {
connection= DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
logger.error("数据库建立连接出错:"+e.getMessage(),e);
}
return connection;
}
/**
* 关闭连接
* @param objects
*/
public static void close(Object...objects){
try {
if(objects!=null){
for(Object obj:objects){
if(obj instanceof Connection){
((Connection) obj).close();
}else if(obj instanceof PreparedStatement){
((PreparedStatement) obj).close();
}else if(obj instanceof ResultSet){
((ResultSet) obj).close();
}
}
}
} catch (SQLException e) {
logger.error("数据库连接关闭异常:"+e.getMessage(),e);
}
}
}
数据库连接,操作数据库:
public class Dao {
private static Log logger = LogFactory.getLog(Dao.class);
/**
* 查询所有
* @param sql
* @param c
* @return
*/
public static<T> List<T> queryAll(String sql,Class<T> c){
Connection connection=null;
PreparedStatement pStatement=null;
ResultSet rSet=null;
List<T> list=new ArrayList<T>();
try {
connection=ConnUtil.getConn();
pStatement=connection.prepareStatement(sql);
rSet=pStatement.executeQuery();
while(rSet.next()){
//通过反射赋值
T t=c.newInstance();
//获取所有属性
Field[] fields=c.getDeclaredFields();
//便利属性并赋值
for(Field f:fields){
//获取属性名
String fName=f.getName();
//获取属性值
Object objValue=rSet.getObject(fName);
//给属性设置值
Method method=c.getMethod(setter(fName), f.getType());
method.invoke(t, objValue);
}
list.add(t);
}
} catch (SQLException e) {
logger.error("数据库异常:"+e.getMessage(),e);
}catch (InstantiationException | IllegalAccessException e1 ){
logger.error("反射异常:"+e1.getMessage(),e1);
} catch (NoSuchMethodException e) {
logger.error("方法错误:"+e.getMessage(),e);
} catch (SecurityException e) {
logger.error("安全异常:"+e.getMessage(),e);
} catch (IllegalArgumentException e) {
logger.error("非法转换异常:"+e.getMessage(),e);
} catch (InvocationTargetException e) {
logger.error("InvocationTargetException异常:"+e.getMessage(),e);
}finally{
ConnUtil.close(rSet,pStatement,connection);
}
return list;
}
/**
* 条件查询
* @param sql
* @param c
* @return
*/
public static<T> List<T> queryByCondition(String sql,Class<T> c,Object...objects){
Connection connection=null;
PreparedStatement pStatement=null;
ResultSet rSet=null;
List<T> list=new ArrayList<T>();
try {
connection=ConnUtil.getConn();
pStatement=connection.prepareStatement(sql);
if(objects!=null){
for(int i=0;i<objects.length;i++){
pStatement.setObject(i+1, objects[i]);
}
}
rSet=pStatement.executeQuery();
ResultSetMetaData resultSetMetaData=rSet.getMetaData();
int count=resultSetMetaData.getColumnCount();
while(rSet.next()){
//通过反射赋值
T t=c.newInstance();
for (int i = 0; i < count; i++) {
//获取属性名
String fName=resultSetMetaData.getColumnName(i);
//获取所有属性
Field field=c.getDeclaredField(fName);
//给属性设置值
Method method=c.getMethod(setter(fName), field.getType());
//获取属性值
Object objValue=rSet.getObject(fName);
method.invoke(t, objValue);
}
list.add(t);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
ConnUtil.close(rSet,pStatement,connection);
}
return list;
}
/**
* 更新操作,包括 insert delete update
* @param sql
* @param objects
* @return flag
*/
public static boolean update(String sql,Object...objects){
Connection connection=null;
PreparedStatement pStatement=null;
boolean flag=false;
try {
connection=ConnUtil.getConn();
pStatement=connection.prepareStatement(sql);
if(objects!=null){
for(int i=0;i<objects.length;i++){
pStatement.setObject(i+1, objects[i]);
}
}
flag=pStatement.execute();
} catch (SQLException e) {
e.printStackTrace();
}finally{
ConnUtil.close(pStatement,connection);
}
return flag;
}
private static String setter(String name){
return "set"+name.substring(0,1).toUpperCase()+name.substring(1);
}
}
总结
JDBC操作数据库,看似简单,但是细节很多,需要我们自己管理数据连接,稍不小心会出现连接未关闭的情况,这样会浪费系统的资源,为了避免我们自己管理JDBC,所以出现了很多框架,如Mybatis、hibernate这种ORM持久性框架,他们对JDBC做了很好的封装,另外有Spring框架的支持,不需要我们去额外维护数据库的连接,我们可以把全部精力放在业务的实现上面,但是JDBC是我们必须会的一个非常重要的知识点,熟悉了JDBC的原理,才能更好的理解框架的应用。以上是在学习和做项目过程中总结的几种JDBC用法各有优缺点,希望能对大家的学习有所帮助。
JDBC操作数据库的三种方式比较的更多相关文章
- laravel记录笔记Laravel 连接数据库、操作数据库的三种方式
laravel中提供DB facade(原始查找).查询构造器.Eloquent ORM三种操作数据库方式 1.连接数据库 .env 数据库配置 DB_HOST=localhost dbhost DB ...
- jdbc链接数据库的三种方式
/** * jdbc连接数据库 * @author APPle * */ public class Demo1 { //连接数据库的URL private String url = "jdb ...
- JDBC注册驱动的三种方式
JDBC注册驱动的三种方式 1.通过导入的JDBC的驱动包拿到的com.mysql.jdbc.Driver对象,利用java.sql.DriverManager对象的DriverManager.reg ...
- Android开发之使用sqlite3工具操作数据库的两种方式
使用 sqlite3 工具操作数据库的两种方式 请尊重他人的劳动成果,转载请注明出处:Android开发之使用sqlite3工具操作数据库的两种方式 http://blog.csdn.net/feng ...
- Code First03---CodeFirst根据配置同步到数据库的三种方式
上一节我们说到使用Fluent API对实体的配置,但是有一个问题了,在业务中我们可以用到的实体很多,那是不是每个都需要这样去配置,这样就造成我们重写的OnModelCreating方法很庞大了.所以 ...
- Yii框架操作数据库的几种方式与mysql_escape_string
一.Yii操作数据库的几种选择 1,PDO方式. $sql = "";//原生态sql语句 xx::model()->dbConnection->createComma ...
- PHP连接MySQL数据库的三种方式(mysql、mysqli、pdo)
PHP与MySQL的连接有三种API接口,分别是:PHP的MySQL扩展 .PHP的mysqli扩展 .PHP数据对象(PDO) ,下面针对以上三种连接方式做下总结,以备在不同场景下选出最优方案. P ...
- JDBC注册驱动程序的三种方式
1. Class.forName("com.mysql.jdbc.Driver");//加载数据库驱动 Class.forName("com.mysql.jdbc.Dri ...
- php连接MySQL数据库的三种方式(mysql/mysqli/pdo)
引言 PHP与MySQL的连接有三种API接口,分别是:PHP的MySQL扩展 .PHP的mysqli扩展 .PHP数据对象(PDO) ,下面针对以上三种连接方式做下总结,以备在不同场景下选出最优方案 ...
随机推荐
- UVA10692:Huge Mods
题面 传送门 题意 输入正整数a1,a2,a3..an和模m,求a1^a2^...^an mod m Sol 首先有\[ a^b\equiv \begin{cases} a^{b\%\phi(p)}~ ...
- 在Service中抛出异常事务未回滚问题分析与解决
1.问题提出:在service中写方法时,抛出了一个Exception, 本来目的是为了让事务回滚, 但事实上没有回滚,产生了脏数据.代码如下:@Override@Transactionalpubli ...
- 关系型数据库工作原理-数据特征统计分析(翻译自Coding-Geek文章)
本文翻译自Coding-Geek文章:< How does a relational database work>.原文链接:http://coding-geek.com/how-data ...
- 未来已来,腾讯AI计算网络
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:由鹅厂网事发表在云+社区 "鹅厂网事"由深圳市腾讯计算机系统有限公司技术工程事业群网络平台部运营,我们希望与业界各位志同道合的伙伴交流 ...
- MongoDB系列一(查询).
一.简述 MongoDB中使用find来进行查询.查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合.默认情况下,"_id"这个键总是被返回,即便是没有指定要返回这 ...
- Lintcode249 Count of Smaller Number before itself solution 题解
[题目描述] Give you an integer array (index from 0 to n-1, where n is the size of this array, data value ...
- 关于browser-sync(在多个设备上进行网页调试)的问题点总结
最近在看响应式网站的开发视频,其中有一部分非常有用,就是在多个设备上进行网页调试,通过使用browser-sync来实现,具体的步骤可以参照官网(http://www.browsersync.cn/) ...
- 关闭NetworkManager的作用
author: headsen chen date: 2017-11-21 13:34:23 个人原创 重启网卡后,会造成网卡失效,报错如下: Bringing up interface eth0 ...
- 数据库操作sql
一.把从另外一张表里查到的值插入到前表: 1. 表结构完全一样 insert into 表1 select * from 表2 2. 表结构不一样(这种情况下得指定列名) insert into 表1 ...
- 1-7 hibernate关联关系映射
1.关联关系分为单向关联(一对一,一对多,多对一,多对多),多向关联(一对一,一对多,多对多). 2.单向一对一主键关联实例 需要为one-to-one元素指定constrained属性值为true. ...