Java数据库连接核心代码,这一篇就够了。
文章适合于刚入行不久或即将开始学习JAVA的小伙伴,你将看到鲜活的真实错误案例、代码开发需求清单,还有学习的注意事项。
JDBC概述
JDBC概述 | Java Database Connectivity的缩写,即JAVA数据库连接,规范客户端如何访问第三方数据库。 (以下以JDBC_mysql代码为例) |
学习资源路径 | [视频教程,5个半小时]:https://www.bilibili.com/video/BV1Bt41137iB(动力节点杜老师,课讲得还是很赞的!) |
前置学习 | JAVA语言基础有全面的学习、熟悉mysql增删改查的核心代码 |
核心主题 | 实现JAVA对mysql数据库的DQL(查)、DML(增、删、改),以及TCL(事务控制) |
完整六步骤 | 注册驱动-->获取连接-->获取数据库操作对象-->执行访问-->处理结果集-->释放资源 |
JDBC概述 | Java Database Connectivity的缩写,即JAVA数据库连接,规范客户端如何访问第三方数据库。 (以下以JDBC_mysql代码为例) |
学习资源路径 | [视频教程,5个半小时]:https://www.bilibili.com/video/BV1Bt41137iB(动力节点杜老师,课讲得还是很赞的!) |
前置学习 | JAVA语言基础有全面的学习、熟悉mysql增删改查的核心代码 |
核心主题 | 实现JAVA对mysql数据库的DQL(查)、DML(增、删、改),以及TCL(事务控制) |
完整六步骤 | 注册驱动-->获取连接-->获取数据库操作对象-->执行访问-->处理结果集-->释放资源 |
JDBC概述 | Java Database Connectivity的缩写,即JAVA数据库连接,规范客户端如何访问第三方数据库。 (以下以JDBC_mysql代码为例) |
学习资源路径 | [视频教程,5个半小时]:https://www.bilibili.com/video/BV1Bt41137iB(动力节点杜老师,课讲得还是很赞的!) |
前置学习 | JAVA语言基础有全面的学习、熟悉mysql增删改查的核心代码 |
核心主题 | 实现JAVA对mysql数据库的DQL(查)、DML(增、删、改),以及TCL(事务控制) |
完整六步骤 | 注册驱动-->获取连接-->获取数据库操作对象-->执行访问-->处理结果集-->释放资源 |
JDBC应用开发框架
注:JDBC本质是很多工具类的集成,意味着很多代码不仅复用、同时服务多个应用场景,需要结合灵活配置;
本节重点阐述图示第一层、第二层的核心代码错误案例;第三层、第四层在下节Servlet核心练习题进行说明。
核心案例一:JDBC基础层--注册数据库驱动、获取数据库连接
1、注册数据库驱动适合参考底层写成静态代码;
2、IO流结合Properties属性配置文件,实现灵活访问不同数据库,而不用修改代码和重新部署。
//以下是修改前代码
public class JDBCutil {
private static Connection conn;//下方定义静态方法,此处也要对应静态变量
private static PreparedStatement ps;
private static ResultSet rs; //注册驱动写成静态方法,实现mysql驱动注册(不需要再Driver实例化)一旦加载就会运行此块而且驱动一直存在。
static {
try {
Class c = class.forName(com.mysql.jdbc.DriverManage);//错误标记_Class大写;括号类是方法传参要加引号; 而不是DriverManage
} catch (ClassNotFoundException e) {
e.printStackTrace();}
}
public static Connection getConnection() throws IOException, SQLException {//
Properties pro = new Properties();
FileInputStream fis = null;
fis = new FileInputStream("/homework/src/jdbc.properties");//错误标记_有时候报错是因为没有写完整路径
pro=fis_read();//错误标记_ pro=fis_read(),虽然是形似
String url = pro.getProperty("url");
String username = pro.getProperty("username");
String password = pro.getProperty("password");
Connection conn = DriverManager.getConnection(url, username, password);
return conn; }
}
//-----------以下是对应的jdbc.properties配置文件代码-------------------------------------//
url=jdbc:mysql://localhost:3306/JDBCTest##错误标记_有中文时要在配置文件的url字符串加上“?characterEncoding=gbk”
username=root
password=123
//以下是修改后代码
public class JDBCutil {
private static Connection conn;//下方定义静态方法,此处也要对应静态变量
private static PreparedStatement ps;
private static ResultSet rs; //注册驱动写成静态方法,实现mysql驱动注册(不需要再Driver实例化)一旦加载就会运行此块而且驱动一直存在。
static {
try {
Class c = Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();}
}
public static Connection getConnection() throws IOException, SQLException {//
Properties pro = new Properties();
FileInputStream fis = null;
fis = new FileInputStream("/home/psdz/Documents/05javascript/ideasave/Servlet/homework/src/jdbc.properties");
pro.load(fis);
String url = pro.getProperty("url");
String username = pro.getProperty("username");
String password = pro.getProperty("password");
Connection conn = DriverManager.getConnection(url, username, password);
return conn; }
}
//-----------以下是对应的jdbc.properties配置文件代码-------------------------------------//
url=jdbc:mysql://localhost:3306/JDBCTest?useUnicode=true&characterEncoding=utf-8
username=root
password=123
```
核心案例二:JDBC服务--数据库新增数据
重点要掌握INSERT语句的提前编译和占位补值等,另外实际项目中经常将查询的数据落到一个实体类,并存在集合中。
//以下是修改前代码
Connection conn = JDBCutil.getConnection();//错误标记_不适合作为全局变量,因为服务层每个方法都会涉及释放资源,再调用会报“资源关闭后不能再操作的错误”
public static int insertData(USERS ur) throws IOException, SQLException {
String sql = "INSERT INTO USERS (UserName,PassWord,Sex,Email) VALUES(?,?,?,?)";
int tag = 0;
try {
ps = conn.prepareStatement(sql);
ps.setString(1, ur.getUserName());
ps.setString(2, ur.getPassWord());
ps.setString(3, ur.getSex().charAt(0));//错误标记_避免使用char类型,尽管此处不报错,但后面还有地方会涉及到此处的隐患
ps.setString(4, ur.getEmail());
tag = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace(); }
close();//错误标记_null状态下不用关闭,也因此写在try内
if (tag > 0) {
System.out.println("成功存储数据到JDBC");
return 1; }else {
return 0;
}
}
//USERS类包含UserId、UserName、PassWord、Sex、Email属性,一级封装方法。省略具体代码
//以下是修改后代码
public static int insertData(USERS ur) throws IOException, SQLException {
String sql = "INSERT INTO USERS (UserName,PassWord,Sex,Email) VALUES(?,?,?,?)";
int tag = 0;
try {
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, ur.getUserName());
ps.setString(2, ur.getPassWord());
ps.setString(3, ur.getSex());
ps.setString(4, ur.getEmail());
tag = ps.executeUpdate();
close();
} catch (SQLException e) {
e.printStackTrace(); }
if (tag > 0) {
System.out.println("成功存储数据到JDBC");
return 1; }else {
return 0;
}
}
//USERS类包含UserId、UserName、PassWord、Sex、Email属性,一级封装方法。省略具体代码
核心案例三:JDBC服务--数据库查询
重点要掌握SELECT的提前编译和占位补值等,另外实际项目中经常将查询的数据落到一个实体类,并存在集合中。
//以下是修改前代码
public static List queryData(){
String sql = "SELECT * FROM USERS WHERE existTag = 1";//existTag逻辑删除标签
try {
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
List mylist = new ArrayList();
while(rs.next()){
USERS ur = new USERS();
ur.setUserId(rs.getInt("userId"));//错误标记_字段首字母大写,否则封装的方法命名看起来会有区别
ur.setUserName(rs.getString("UserName"));
ur.setPassWord(rs.getString("PassWord"));
ur.setSex(rs.getString("Sex"));
ur.setEmail(rs.getString("Email"));
mylist.add(ur);
}
} catch (SQLException | IOException e) {
e.printStackTrace(); }
close();//错误标记_null状态下不用关闭,也因此要写在try内
return mylist; //错误标记_null状态下不用返回list,也因此要写在try内
return null;//引用方要配if(非null)
}
//USERS类包含UserId、UserName、PassWord、Sex、Email属性,一级封装方法。省略具体代码
//以下是修改后代码
public static List queryData(){
String sql = "SELECT * FROM USERS WHERE existTag = 1";//existTag逻辑删除标签
try {
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
List mylist = new ArrayList();
while(rs.next()){
USERS ur = new USERS();
ur.setUserId(rs.getInt("UserId"));
ur.setUserName(rs.getString("UserName"));
ur.setPassWord(rs.getString("PassWord"));
ur.setSex(rs.getString("Sex"));
ur.setEmail(rs.getString("Email"));
mylist.add(ur);
}
close();
return mylist;
} catch (SQLException | IOException e) {
e.printStackTrace(); }
return null;//引用方要配if(非null)
}
//USERS类包含UserId、UserName、PassWord、Sex、Email属性,一级封装方法。省略具体代码
核心案例四:JDBC服务--数据库更新&逻辑删除
逻辑删除是一种涉及规范,不让存入的数据被真实删除。通过加一个标签字段实现对“数据是否显示”的一个条件判断。
public static int deleteData(String wheresentence){
//物理删除:DELETE FROM table_name [WHERE Clause];逻辑删除改标记
String sql = "UPDATE USERS SET ExistTag=0 " + wheresentence;//错误标记_SQL字符串末尾不能少一个空格
int rowtag = 0;
try {
conn = JDBCutil.getConnection();
ps = conn.prepareStatement(sql);
rowtag = ps.executeUpdate();
close();
} catch (SQLException | IOException e) {
e.printStackTrace();
}
if (rowtag > 0) {
System.out.println("成功逻辑删除数据"); }
return rowtag;}
核心案例五:JDBC服务--事务控制
事务控制是为了保持数据的完整性,避免一批数据中个别异常数据影响中断后,实际改动了前面一部分数据。
属性setAutoCommit()默认是true,要在操作数据库前改成false,并在操作结束后提交。
public static void main(String[] args) throws IOException, SQLException {
var conn = JDBCutil.getConnection();
PreparedStatement ps =null;
ResultSet rs = null;
try {
conn.setAutoCommit(false);
String sql = "update t_trans SET AccountBalance=AccountBalance+? where AccountName=?";
ps = conn.prepareStatement(sql);
//第一次占位改值
ps.setString(2,"zs");
ps.setDouble(1,-5000);
int tag = ps.executeUpdate();
System.out.println("修改"+tag+"行数据进行中");
//制造空指针异常,为了看事务被中断的效果
//String k = null;
//k.toString();
//第二次占位改值
ps.setString(2,"zs");
ps.setDouble(1,10000);
tag += ps.executeUpdate();
System.out.println(tag == 2? "连续修改两次数值成功":"连续修改两次数值失败");
//事务自动提交重新开启
conn.commit();
} catch (SQLException throwables) {
throwables.printStackTrace(); }
//释放资源
JDBCutil.close(rs,ps,conn);
}
核心案例六:JDBC服务--释放资源写成单独方法
释放资源的方法适合和其他方法一起写在JDBC服务层上,过程中涉及到的对象由全局变量生成,减少不必要的代码重复
释放的顺序与对象对象的顺序相反,依次是:ResultSet-->PreparedStatement-->Connection
public static void close(ResultSet rs, Statement ps, Connection conn){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrace(); }
}
if(ps!=null){
try{
ps.close();
}catch(SQLException e){
e.printStackTrace(); }
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace(); }
}
}
最后,谢谢查看,更多同类核心实战案例请查看往期文章。