Java JDBC的简单使用
一.思路
Ⅰ.单体上看:
① 导入相关 jar 包
② 加载 数据库驱动
③ 获取数据库连接
④ 执行数据库相关操作
⑤ 关闭数据库连接
Ⅱ.从整体上看
① Service 层获取数据库连接,负责整体的逻辑处理
② Dao 层负责将数据库数据处理、封装或转换成Service 层需要的数据
③ Util 层,提供数据库连接、查询、关闭等操作
个人观点:在不考虑使用数据库连接池的情况下,我是这么想的。具体想法如下:
1.我为什么要在 Service层上获取数据库连接?
我的想法是,并非每个人的业务都只需要对数据库执行一次操作,可能要执行2次操作,这谁说的准呢?看功能需求,自己来,我觉得这样会好一点;再说,并非每个人都有能力写出一个复杂的 sql 语句,不行的时候拆成几条 sql 执行,再根据数据结果执行逻辑操作
2.Dao负责将数据库执行的结果封装返回,毕竟咱现在是面向对象,不能向学C的时候那么干了
3.不足?
每一个 Service 逻辑操作都要获取和关闭连接,要知道数据库连接是一个比较耗时的操作,这也没办法,没用连接池
二.代码
上面那么多废话,下面直接看看代码吧,不足的地方忘大家指正…
Util层
public class DBUtile {
private static String MYSQL_URL = "jdbc:mysql://localhost:3306/mytest";
private static String DRIVER = "com.mysql.jdbc.Driver";
private static String MYSQL_ROOT = "root";
private static String MYSQL_PASSWORD = "123456";
private static Connection connection;
public static Connection getConnection(){
try {
Class.forName(DRIVER); //加载数据库驱动
connection = DriverManager.getConnection(MYSQL_URL,MYSQL_ROOT,MYSQL_PASSWORD); //获取连接对象
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
public static boolean closeConnection(){
try {
if(connection!=null){
connection.close();
connection = null;
}
return true;
}catch (Exception e){
System.out.println("无法关闭 数据库连接,位置,util包下的DBUtil类");
return false;
}
}
private PreparedStatement setParam( PreparedStatement p ,Object ... param){
try {
for(int i = 0; i < param.length;i++) { //从下标1开始
String typeName = param[i].getClass().getName();
if ("java.lang.Integer".equals(typeName)) {
p.setInt(i + 1, (Integer) param[i]);
} else if ("java.lang.Long".equals(typeName)) {
p.setLong(i + 1, (Long) param[i]);
} else if ("java.lang.String".equals(typeName)) {
p.setString(i + 1, (String) param[i]);
} else if ("java.lang.Float".equals(typeName)) {
p.setFloat(i + 1, (Float) param[i]);
} else if ("java.lang.Double".equals(typeName)) {
p.setDouble(i + 1, (Double) param[i]);
} else if ("java.lang.Byte".equals(typeName)) {
p.setByte(i + 1, (Byte) param[i]);
} else if ("java.lang.Short".equals(typeName)) {
p.setShort(i + 1, (Short) param[i]);
} else {
throw new Exception("传入数据库的是:非基本类型");
}
}
}catch (Exception e){
System.out.println("请仔细检查sql语句,参数的类型和位置");
}
return p;
}
/**
* 查询 ,返回结果集,这里并没有关闭数据库连接,请自己关闭
*/
public ResultSet executeQuery(String sql,Connection con,Object ... param){
System.out.println("executeQuery....");
ResultSet rs = null;
Connection conn = con;
try {
PreparedStatement p = conn.prepareStatement(sql);
if(param.length > 0){ //param数组有值 即代表着 有传入参数,并且sql语句中含有占位符
p = setParam(p,param);
}
rs = p.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
return rs;
}
/**
* 修改
*/
public int executeUpdate(String sql,Connection con,Object ... param){
System.out.println("executeUpdate....");
int rs = 0;
Connection conn = con;
try {
PreparedStatement p = conn.prepareStatement(sql);
if(param.length > 0){
p = setParam(p,param);
}
rs = p.executeUpdate();
}catch (Exception e){
System.out.println("DBUtile executeUpdate 异常。。。");
e.printStackTrace();
}
return rs;
}
/**
* 删除
*/
public int executeDelete(String sql,Connection con,Object ... param){
System.out.println("executeUpdate....");
int rs = 0;
Connection conn = con;
try {
PreparedStatement p = conn.prepareStatement(sql);
if(param.length > 0) {
p = setParam(p, param);
}
}catch (Exception e){
System.out.println("DBUtile executeUpdate 异常。。。");
e.printStackTrace();
}
return rs;
}
}
Dao层
public class OperationDao {
public OperationDao() {
}
/**
* 获取 DBUtile类从数据库的查询结果,封装成自己/业务 需要的结果并返回
* @param sql sql语句
* @param con service层连接对象
* @param param 参数数组
* @return 自己数据库查询后想要的对象或数据,此处是boolean
*/
public boolean QueryCarName(String sql, Connection con,Object ... param) {
Connection conn = null; //这个param要注意一下
try {
conn = con;
DBUtile utile = new DBUtile();
ResultSet rs = utile.executeQuery(sql,conn);
while (rs.next()){
String licensePlate = rs.getString("licensePlate");
int id = rs.getInt("id");
String brand = rs.getString("brand");
System.out.println("----------------------->"+licensePlate+",id :"+idd+",brand:"+brand);
}
}catch (SQLException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
return false;
}
}
Service层
public class CarOperationService {
@Inject //和 @Autowired 一样,都是注入一个对象,你也可以通过new的方式,创建一个 Dao对象
private CarOperationDao carOperationDao;
public CarOperationService(){
}
public boolean modifyCamereName(int id, String oldName, String newName){
System.out.println("MonitorService do modifyCamereName...");
String sql = "update car set DriverName = ?,DriverAge = ? where id = ?";
try{
Connection conn = DBUtile.getConnection(); //获取连接
carOperationDao.updateCarName(sql,conn,"张三",22,1);
}finally {
DBUtile.closeConnection();
}
return false;
}
}
三.注意事项
1.在代码中的有这么一行代码(这个在 Dao 层 和 Util层):
public int executeUpdate(String sql,Connection con,Object ... param){
这里的重点是: Object … param,对,就是这个玩意;
先来看一张图片吧!
你会在 Util 层看到这么一句:
if(param.length > 0){
p = setParam(p,param);
}
没错,param 就是一个数组,不过它的长度是取决于传过来的参数,当然你也可以不传,这里的效果就和图片的效果是一样的,它的本质就是一个 Object的数组;
再看之前的代码吧,比如:你要调用方法:
public ResultSet executeQuery(String sql,Connection con,Object ... param)
你的调用可以是:
对象.executeQuery(sql,con,id,name); //这里的 id,name,会被存放在 param 的数组里,当然这里你还可以传更多的参数
对象.executeQuery(sql,con); //也可以是这样,没有其它参数,这里也不会报错
2.我犯过的坑,对没错,我就在 Object … param 摔了跟头,当时我要根据条件更新数据库的一条数据,然后 sql语句里面有 ?号占位符,预编译后,我没有传对应的参数过去,但是调用根本是不会报错的,所以,使用 Object … param这个的时候一定要注意,有没有参数要传,参数位置是否与sql语句中的对应
3.我的发现
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
当时匆匆一瞥,看到了这个玩意,小本本记下来