文章目录

  • ​​JDBC​​
  • ​​使用JDBC的基本步骤​​
  • ​​JDBC 工具类创建​​
  • ​​数据库的CRUD操作​​
  • ​​使用单元测试JUNIT,测试代码步骤​​
  • ​​Dao模式​​
  • ​​Statement安全问题​​
  • ​​PrepareStatement​​

JDBC

JAVA Database Connectivity java数据库连接
说白了:JDBC就是sun公司提供的一种数据库访问规则、规范。由于数据库种类较多,并且java语言使用比较广泛,sun公司就提供了一种规范,让其他的数据库提供商去实现底层的访问规则。 我们的java程序只要使用sun公司提供的jdbc驱动即可。

使用JDBC的基本步骤

  • 导入驱动
    java项目文件(就是自己创建的peoject)右击 -> Build Path -> Configure Build Path -> Libraries ->Add External JARS -> 选择自己已经下载的 mysql-connector-java-8.0.16.jar(本人下载的是8.0.16版本)
  • 注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
  • 建立连接
Connection conn = null;
conn = DriverManager.getConnection("jdbc:mysql://localhost/javatest?serverTimezone=UTC", "用户名", "密码");
  • 创建Statement
Statement st = null;
st = conn.createStatement();
  • 执行sql,得到ResultSet
//以查询为例
String sql = "select * from peo";
rs = st.executeQuery(sql);
  • 遍历结果集
String sql = "select * from peo";
rs = st.executeQuery(sql);
while(rs.next()) {
String id = rs.getString("Pno");
String name = rs.getString("Pname");
String pwd = rs.getString("Paswd");
System.out.println("id:"+id+" name:"+name+" pwd:"+pwd);
}
  • 释放资源
//释放顺序:rs -> st -> conn;
//比如conn
try {
if(conn != null) {
conn.close();
System.out.println("conn关闭成功");
}}catch (SQLException e) {
e.printStackTrace();
}finally {
conn = null;
}

这上面的写一个java文件里面的话,着实是很臃肿,所有引入JDBC工具类,可以使代码更加灵活

JDBC 工具类创建

1. 资源释放工作的整合
就是资源释放代码写到一个工具类 JDBCUtil.java 里面
JDBCUtil.java

/*
* 释放资源
* */

public static void release(Connection conn,Statement st,ResultSet rs) {
closeRs(rs);
closeSt(st);
closeConn(conn);
}
private static void closeRs(ResultSet rs) {
try {
if(rs != null) {
rs.close();
System.out.println("rs关闭成功");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
rs = null;
}
}
private static void closeSt(Statement st) {
try {
if(st != null) {
st.close();
System.out.println("st关闭成功");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
st = null;
}
}
private static void closeConn(Connection conn) {
try {
if(conn != null) {
conn.close();
System.out.println("conn关闭成功");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
conn = null;
}
}

然后在主程序finally里面直接调用release那个函数即可

finally {
JDBCUtil.release(conn, st, rs);
}

2. 驱动预防二次注册
    Driver这个类里面有静态代码库,里面有一段代码是
  ​​​java.sql.DriverManager.registerDriver(new Driver());​​​ 一上来就执行了,所以等同于我们注册了两次驱动。 其实没这个必要的。
最后我们一般注册的时候会用:
  ​​Class.forName("com.mysql.cj.jdbc.Driver");​

3. 使用properties配置文件

  • 在src底下声明一个文件 jdbc.properties,里面的内容(不要引号,不要分号)为:
driverClass = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost/javatest?serverTimezone=UTC
name = root
passwd = 52151
  • 在工具类里,使用静态代码块,读取属性
static String driverClass = null;
static String url = null;
static String name = null;
static String passwd = null;
static {
try {
//创建一个属性配置对象
Properties properties = new Properties();
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
//导入输入流
properties.load(is);
//读取属性
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
name = properties.getProperty("name");
passwd = properties.getProperty("passwd");
}
catch (Exception e) {
e.printStackTrace();
}
}

数据库的CRUD操作

  • Insert
//insert 返回的是影响的行数  >0操作成功  否则失败
sql = "INSERT INTO peo VALUES(\"5\",\"ds5\",\"1513213\");";
int results = st.executeUpdate(sql);
if(results > 0 ) {
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
  • Delete
sql = "DELETE FROM peo where Pno= '5';";
results = st.executeUpdate(sql);
if(results > 0 ) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
  • Query
String sql = "select * from peo";
rs = st.executeQuery(sql);
//遍历结果集
while(rs.next()) {
String id = rs.getString("Pno");
String name = rs.getString("Pname");
String pwd = rs.getString("Paswd");
System.out.println("id: "+id+" name: "+name+" pwd: "+pwd);
}
  • Update
sql = "UPDATE peo SET Paswd = '88889' WHERE Pno = '4';";
results = st.executeUpdate(sql);
if(results > 0 ) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}

使用单元测试JUNIT,测试代码步骤

  1. 定义一个类,比如 TestDemo.java,里面定义方法 testXXX. 必须以test开头
  2. 添加Junit支持
    右键工程 —> add Library —> Junit —> Junit4/5
    注意是在Classpath里面添加
  3. 在方法上面加上注解,其实就是一个标记,没有 @Test 标记Junit不认识
@Test
public void testQuery() {
...
}
  1. 光标选中方法名,右键执行单元测试(run as 里面)。或者是打开outline试图,然后选中方法名执行即可。

Dao模式

Date Access Object 数据访问对象

  1. 新建一个dao接口 peoDao.java,里面声明数据库访问规则
package com.yl.dao.demo;

import java.util.List;
import java.util.Map;

public interface peoDao {
//查询所有
void findAll();
//登录
void login(String username,String password);
//添加
void insert(String username,String password);
//删除
void delete(String id);
//更新 根据id 更新用户名
void update(String id,String username);
//通过返回List来遍历输出
List< Map<String,String> > findall();
//返回int得到几行受到影响
int delete1(String id);
}
  1. 新建一个dao实现类 peoDaoImpl.java,具体实现早前定义的规则
package com.yl.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yl.dao.demo.peoDao;
import com.yl.dao.util.JDBCUtil;

public class peoDaoImpl implements peoDao {

@Override
public void findAll() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
st = conn.createStatement();
String sql = "select * from p_user";
rs = st.executeQuery(sql);
// 遍历结果集
while (rs.next()) {
String id = rs.getString("Pno");
String name = rs.getString("Pname");
String pwd = rs.getString("Paswd");
System.out.println("id: " + id + " name: " + name + " pwd: " + pwd);
}

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, st, rs);
}

}

@Override
public void login(String username, String password) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
String sql = "select * from p_user where Pname = ? and Paswd = ?";
// 预先对sql语句执行语法的校验,? 对应的内容,后面不管传什么进来 都当成字符串
PreparedStatement ps = conn.prepareStatement(sql);// 比Statement 安全
// ?对应索引从 1 开始哦
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
// 遍历结果集
if (rs.next()) {
System.out.println("登录成功");
} else
System.out.println("登陆失败");

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, st, rs);
}
}

@Override
public void insert(String username, String password) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement ps = null;
int res;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
String sql = "insert into p_user values('10' , ? , ?);";
// 预先对sql语句执行语法的校验,? 对应的内容,后面不管传什么进来 都当成字符串
ps = conn.prepareStatement(sql);// 比Statement 安全
// ?对应索引从 1 开始哦
ps.setString(1, username);
ps.setString(2, password);
res = ps.executeUpdate();
// 遍历结果集
if (res > 0) {
System.out.println("插入成功");
} else
System.out.println("插入失败");

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, ps);
}
}

@Override
public void delete(String id) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement ps = null;
int res;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
String sql = "delete from p_user where Pno = ?";
// 预先对sql语句执行语法的校验,? 对应的内容,后面不管传什么进来 都当成字符串
ps = conn.prepareStatement(sql);// 比Statement 安全
// ?对应索引从 1 开始哦
ps.setString(1, id);
res = ps.executeUpdate();
// 遍历结果集
if (res > 0) {
System.out.println("删除成功");
} else
System.out.println("删除失败");

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, ps);
}
}

@Override
public void update(String id, String username) {

Connection conn = null;
PreparedStatement ps = null;
int res;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
String sql = "update p_user set Pname = ? where Pno = ? ";
// 预先对sql语句执行语法的校验,? 对应的内容,后面不管传什么进来 都当成字符串
ps = conn.prepareStatement(sql);// 比Statement 安全
// ?对应索引从 1 开始哦
ps.setString(1, username);
ps.setString(2, id);
res = ps.executeUpdate();
// 遍历结果集
if (res > 0) {
System.out.println("更新成功");
} else
System.out.println("更新失败");

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, ps);
}
}

@Override
public List<Map<String, String>> findall() {
List< Map<String,String> > peos= new ArrayList<>();
Map<String,String> peo = new HashMap<>();
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
st = conn.createStatement();
String sql = "select * from p_user";
rs = st.executeQuery(sql);
// 遍历结果集
while (rs.next()) {
String id = rs.getString("Pno");//id
String name = rs.getString("Pname");//name
peo.put(id,name);
//System.out.println("id: " + id + " name: " + name + " pwd: " + pwd);
}
peos.add(peo);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, st, rs);
}
return peos;
}

@Override
public int delete1(String id) {
Connection conn = null;
PreparedStatement ps = null;
int res = 0;
try {
// TODO Auto-generated method stub
// 获取连接对象
conn = JDBCUtil.getConn();
// 创建Statement
String sql = "delete from p_user where Pno = ?";
// 预先对sql语句执行语法的校验,? 对应的内容,后面不管传什么进来 都当成字符串
ps = conn.prepareStatement(sql);// 比Statement 安全
// ?对应索引从 1 开始哦
ps.setString(1, id);
res = ps.executeUpdate();

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
JDBCUtil.release(conn, ps);
}
return res;
}
}
  1. 新建一个TestDemoDaoImpl直接使用实现
package com.yl.dao.test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import com.yl.dao.demo.peoDao;
import com.yl.dao.impl.peoDaoImpl;

public class TestUserDaoImpl {
@Test
public void testFindAll() {
peoDao dao = new peoDaoImpl();
dao.findAll();
}
@Test
public void testLogin() {
peoDao dao = new peoDaoImpl();
dao.login("yl", "123456");
// dao.login("yl","123456 ' or '1=1'");
}
@Test
public void testInsert() {
peoDao dao = new peoDaoImpl();
dao.insert("zk", "123147");
}
@Test
public void testDelete() {
peoDao dao = new peoDaoImpl();
dao.delete("10");
}
@Test
public void testUpdate() {
peoDao dao = new peoDaoImpl();
dao.update("4", "hhh");
}
@Test
public void testFindall() {
List< Map<String,String> > peos = new ArrayList<>();
peoDao dao = new peoDaoImpl();
peos = dao.findall();
for(Map<String, String> map : peos) {
Iterator<String> it = map.keySet().iterator();
while(it.hasNext()) {
String key = it.next();
System.out.println("id:"+key+" name:"+map.get(key));
}
}
}
@Test
public void testDelete1() {
peoDao dao = new peoDaoImpl();
int ans = dao.delete1("5"); //mysql表里存在三个
System.out.println(ans+"行收到影响"); //完成咯
}
}

Statement安全问题

  1. Statement执行 ,其实是拼接sql语句的。 先拼接sql语句,然后在一起执行。
SELECT * FROM peo WHERE username='admin' AND PASSWORD='100234khsdf88' or '1=1' 
前面先拼接sql语句, 如果变量里面带有了 数据库的关键字,那么一并认为是关键字。 不认为是普通的字符串。

所以一般使用PrepareStatement

PrepareStatement

该对象就是替换前面的statement对象。

相比较以前的statement, 预先处理给定的sql语句,对其执行语法检查。 在sql语句里面使用 ? 占位符来替代后续要传递进来的变量。 后面进来的变量值,将会被看成是字符串,不会产生任何的关键字。

String sql = "insert into t_user values(null , ? , ?)";
ps = conn.prepareStatement(sql);
//给占位符赋值 从左到右数过来,1 代表第一个问号, 永远你是1开始。
ps.setString(1, userName);
ps.setString(2, password);

End?maybe……