JDBC(工具类,CRUD,Dao模式、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……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值