一、ResultSet :结果集的数据表
举例1:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcTest {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//获取数据库连接
conn = JdbcUtils.getConnection();
//准备sql
String sql = "update student set address = '北京市' where id = 13" ;
//获取Statement对象
stmt = conn.createStatement();
//准备执行
int count = stmt.executeUpdate(sql);
System.out.println("更新成功");
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.close(stmt,conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
//声明成员属性
private static String driver = null ;
private static String url = null ;
private static String user = null ;
private static String password = null ;
// 提供一个静态代码块
static{
try {
//创建一个属性集合类对象
Properties prop = new Properties() ;
//读取配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().
getResourceAsStream("jdbc.properties");
prop.load(inputStream);
//通过key获取value
driver = prop.getProperty("driver");
url = prop.getProperty("url") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
//注册驱动
Class.forName(driver) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private JdbcUtils(){}
//获取数据连接对象的方式
public static Connection getConnection(){
Connection conn = null ;
try {
conn = DriverManager.getConnection(url,user,password) ;
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//提供关闭资源方法:针对DQL语句:查询获取结果集,关闭相关资源
public static void close(ResultSet rs, Statement stmt,Connection conn) throws SQLException {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
conn.close();
}
}
//针对DDL,DML操作:不需要ResultSet
public static void close(Statement stmt,Connection conn) throws SQLException {
close(null,stmt,conn);
}
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
举例2:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcTest2 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
//获取数据库的链接对象
conn = JdbcUtils.getConnection();
//获取执行对象
stmt = conn.createStatement();
//准备sql
String sql = "select * from emp" ;
//执行查询
//public ResultSet executeQuery(String sql)
rs = stmt.executeQuery(sql);
//boolean next():判断结果集数据表中是否存在有效数据,true,就向前移动一行
//防止如果没有数据了,不能在移动了,否则就异常了,加入判断
/* //第一次
if(rs.next()){ //true
//获取
//XXX getXXX(int columnIndex):列的索引获取:第一列就是1
//XXX getXXX(String columnName) 列的名称获取
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
System.out.println(id+"\t"+name+"\t"+address);
}
//第二次
if(rs.next()){ //true
//获取
//XXX getXXX(int columnIndex):列的索引获取:第一列就是1
//XXX getXXX(String columnName) 列的名称获取
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
System.out.println(id+"\t"+name+"\t"+address);
}
//第三次
if(rs.next()){ //true
//获取
//XXX getXXX(int columnIndex):列的索引获取:第一列就是1
//XXX getXXX(String columnName) 列的名称获取
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
System.out.println(id+"\t"+name+"\t"+address);
}
//第四次
if(rs.next()){ //true
//获取
//XXX getXXX(int columnIndex):列的索引获取:第一列就是1
//XXX getXXX(String columnName) 列的名称获取
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
System.out.println(id+"\t"+name+"\t"+address);
}*/
//改进:代码重复很高,循环:while循环
while(rs.next()){
//获取
//XXX getXXX(int columnIndex):列的索引获取:第一列就是1
//XXX getXXX(String columnName) 列的名称获取
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
System.out.println(id+"\t"+name+"\t"+address);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.close(rs,stmt,conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
二、需求:要通过jdbc查询员工表(ResultSet的使用)
/* 需求:
* 现在将emp表中的每一条记录封装到实体类中:Emp (员工类),将整个的员工的所有数据最终
* 存储在List<Emp>,将员工的信息遍历出来!
*
* 1)需要有一个员工类Emp它需要和员工表的emp的字段一一对应
* id 属性
* name属性
* address属性
*
* 2)定义一个接口:
* EmpDao
* 查询所有的员工信息
* public List<Emp> findAllEmp() ;
*
* 3)定义一个接口的实现类
* EmpDaoImpl
* public List<Emp> findAllEmp() {
* //创建空的集合
* //jdbc操作----查询所有员工表数据
* }
* 4)在测试类中:可以通过接口多态的方式进行测试,完成数据查询!
*/
import com.qf.dao.EmpDao;
import com.qf.dao.impl.EmpDaoImpl;
import com.qf.entity.Emp;
import java.util.List;
public class JdbcTest3 {
public static void main(String[] args) {
//查询所有员工信息
EmpDao ed = new EmpDaoImpl() ;
List<Emp> empList = ed.findAllEmp();
for(Emp emp :empList){
// System.out.println(emp);
System.out.println(emp.getId()+"\t"+emp.getName()+"\t"+emp.getAddress());
}
}
}
/* 属性和emp表中字段对应
* 提供公共访问方法
*/
public class Emp {
private Integer id ; //员工编号
private String name ;//员工姓名
private String address ; //员工的住址
public Emp() {
}
public Emp(Integer id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
import com.qf.entity.Emp;
import java.util.List;
/* 针对员工数据库访问接口层
*/
public interface EmpDao {
//查询所有
public List<Emp> findAllEmp() ;
//查询单个员工信息
public Emp findEmpById(Integer id) ;
//添加员工信息
public void addEmp(Emp emp) ;
//删除员工信息:通过id删除
//修改员工信息
//查询总记录数
public int getTotalCount() ;
}
import com.qf.dao.EmpDao;
import com.qf.entity.Emp;
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* @Author:zhangyang
* @Date: 11:05
* @Version 1.0
* 针对员工的数据访问接口实现层
*/
public class EmpDaoImpl implements EmpDao {
@Override
public List<Emp> findAllEmp() {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
//创建一个集合对象
List<Emp> list = new ArrayList<Emp>() ;
//创建数据库的连接对象
conn = JdbcUtils.getConnection();
//获取执行对象
stmt = conn.createStatement() ;
//sql语句
String sql = "select * from emp" ;
//查询
rs = stmt.executeQuery(sql);
//声明变量emp:类型Emp
Emp emp = null ;
//遍历结果集
while(rs.next()){
//通过列的名称来获取
//创建员工对象
emp = new Emp() ;
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String address = rs.getString("address") ;
//封装员工数据
emp.setId(id);
emp.setName(name);
emp.setAddress(address);
//将员工添加集合中
list.add(emp) ;
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.close(rs,stmt,conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return null ;
}
/**
* 根据员工编号查询员工信息
* @param id 员工编号
* @return 返回的当前员工
*/
@Override
public Emp findEmpById(Integer id) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try{
//获取连接
conn = JdbcUtils.getConnection();
stmt = conn.createStatement() ;
String sql = "select * from emp where id =5" ;
rs = stmt.executeQuery(sql) ;
Emp emp = null ;
while(rs.next()){
emp = new Emp() ;
int empId = rs.getInt(1) ;
String empName = rs.getString(2) ;
String empAddress = rs.getString(3) ;
emp.setId(empId);
emp.setName(empName);
emp.setAddress(empAddress);
}
return emp ;
}catch (SQLException e){
e.printStackTrace();
}finally {
try {
JdbcUtils.close(rs,stmt,conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public int getTotalCount() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//获取连接
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
String sql = "select count(id) from emp";
ResultSet resultSet = stmt.executeQuery(sql);
int count = 0;
while (rs.next()) {
count = rs.getInt("id");
System.out.println(count);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
JdbcUtils.close(rs, stmt, conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0 ;
}
/**
* 添加员工信息
* @param emp 具体的员工对象
*/
@Override
public void addEmp(Emp emp) {
}
}
/*测试类*/
import com.qf.dao.EmpDao;
import com.qf.dao.impl.EmpDaoImpl;
import com.qf.entity.Emp;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/* Junit包使用@Test注解:执行单元测试注解
* @Before:在执行@Test标记的单元测试方法之前,先执行
* 一些业务相关的初始化操作
*
* @After:在执行@Test标记的单元测试方法之后执行:
* 一般释放资源都可以放在这里面
*/
public class JdbcTest {
/* @Before
public void init(){
//初始化操作
System.out.println("初始化操作完成...");
}*/
@Test
//测试查询所有
public void testFindAll(){
//测试EmpDao中的接口 findAllEmp()
EmpDao empDao = new EmpDaoImpl() ;
List<Emp> list = empDao.findAllEmp();
for(Emp emp:list){
System.out.println(emp);
}
}
//测试根据id查询某个员工
@Test
public void testFindEmpById(){
EmpDao empDao = new EmpDaoImpl() ;
Emp emp = empDao.findEmpById(5);
System.out.println(emp);
}
/*@After //在执行单元测试方法之后执行
public void myclose(){
System.out.println("资源被关闭");
}*/
}
三、Statement对象执行DDL,DML语句的弊端
-
使用Statement模拟登录操作
键盘录入用户名和密码,和数据库中存储的用户名和密码进行对比!
如果一致,提示登录成功,否则失败 -
SQL注入:
使用Statement执行静态sql语句:存在字符串拼接 (存在安全问题!)
SELECT * FROM USER WHERE username = ‘sdfsfs’ AND PASSWORD = ‘a’ OR ‘a’ = ‘a’ ;
针对sql的执行效率低
Statement对象.executeUpdate(String sql)/executeQuery(String sql) -
PreparedStatement书写sql—可以有效防止sql注入(推荐)
而且提高的sql的执行效率 -
先将参数化的sql发送数据库:进行预编译完成(通过类型校验)将sql存储在PreparedStatement内存中
SELECT * FROM USER WHERE username = ? AND PASSWORD = ? ; -
直接通过?占位符号给当前进行实际参数赋值!
PreparedStatement.executeUpdate() / executeQuery()
举例:
import com.qf.utils.JdbcUtils;
import java.sql.*;
import java.util.Scanner;
public class StatemetDemo {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//提示并录入
System.out.println("请您输入用户名:");
String username = sc.nextLine() ;
System.out.println("请您输入密码:");
String password = sc.nextLine() ;
//调用登录的功能
boolean flag = isLogin2(username,password) ;
if(flag){
System.out.println("登录成功...");
}else{
System.out.println("对不起,用户名或者密码错误!");
}
}
//使用PreparedStatement对象来完成登录操作
private static boolean isLogin2(String username, String password) {
Connection connection = null ;
PreparedStatement ps = null ;
ResultSet rs = null ;
try {
connection = JdbcUtils.getConnection();
String sql = "select * from user where username = ? and password = ?" ;
System.out.println(sql);
ps = connection.prepareStatement(sql) ;//已经参数化的发送数据库进行编译
//参数赋值
ps.setString(1,username);
ps.setString(2,password);
//执行查询
rs = ps.executeQuery();
return rs.next() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.close(rs,ps,connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
return false ;
}
//登录的功能
//使用statement来操作数据库
private static boolean isLogin(String username, String password) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
//创建数据库连接对象
conn = JdbcUtils.getConnection();
//通过连接对象获取执行对象
stmt = conn.createStatement();
//准备sql语句
//字符串拼接
String sql =
"select * from user where username = '"+username+"' and password = '"+password+"'" ;
System.out.println(sql);
//准备执行
rs = stmt.executeQuery(sql);
return rs.next() ;//如果当前返回true,光标向前移动,就通过用户名和密码查询到!
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
}
四、PreparedStatement:预编译对象的使用(推荐使用预编译sql)
- 步骤:
1)加载驱动
2)获取数据库连接对象
3)准备好参数的sql语句 :带条件的查询 /增删改,都带上? 占位符号
4)获取的预编译对象:将参数化的sql存储在编译对象中
5)给参数进行赋值
6)查询/更新操作
7)释放资源
举例:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class PreparedStatementTest {
public static void main(String[] args) {
Connection conn = null ;
PreparedStatement ps = null ;
try {
//获取数据库的链接对象
conn = JdbcUtils.getConnection();
//准备好参数化的sql
String sql = "insert into emp values(?,?,?) " ;
//通过链接对象获取预编译对象并将sql进行 参数编译(编译当前类型等等)
//PreparedStatement prepareStatement(String sql) throws SQLException
ps = conn.prepareStatement(sql);
//准备参数赋值
//void setXXX(int parameterIndex,int x)
//参数1:第几个占位符号的索引值(1开始)
//参数2;当前给参数1赋的实际参数
ps.setInt(1,7);
ps.setString(2,"李渊") ;
ps.setString(3,"南窑国际") ;
//执行更新的通用操作;int executeUpdate()
//执行查询的通用澳洲:ResultSet executeQuery()
int count = ps.executeUpdate();
System.out.println(count);
System.out.println("更新成功");
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.close(ps,conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
五、数据库连接池(池化技术)
-
手动封装工具:JdbcUtils:存在问题
对于增删查改,都需要获取连接对象(Connection:需要被频繁的创建-----销毁资源过多) -
连接池:
可以管理很多个连接对象,里面有一些参数配置,最大连接数量,最大激活数量,最小数量
空闲数量,最大等待时间,都可以对连接池进行优化,连接对象使用完毕,不会从内存被释放而是继续归还到
连接池中: -
java.sql.DataSource:物理数据源的链接:替代DrvierManager
举例:
dbcp
c3p0:早期的连接池
druid: 德鲁伊连接池(推荐)
最大连接数:10
当前创建第 11个对象:— jvm输出错误日志,可将某个Connection使用完毕close()
归还到连接池中,第11个连接对象就可以使用! -
对于c3p0的使用:
1)两个jar包
核心包:c3p0-0.9.1.2.jar
依赖包:mchange-commons-java-0.2.12.jar
举例1:
public class C3p0Demo {
public static void main(String[] args) throws SQLException {
//创建c3p0的连接池对象
ComboPooledDataSource pooledDataSource = new ComboPooledDataSource() ;
//那么就自动读取c3p0-config.xml文件的defalut-config的配置
//如果执行的有参构造方式:读取配置文件中named-config
//Connection getConnection() throws SQLException;重写了DataSource接口的获取连接的方法
for(int x = 1 ; x<=11;x ++){
Connection connection =
pooledDataSource.getConnection();
if(x == 5){
connection.close(); //而是第二个连接对象 归还到连接池中
}
System.out.println(connection);
}
}
}
举例2:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.ConnectionEvent;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/* 加入DruidDataSource(类 实现java.sql.DataSource:物理数据源的链接))以及ThreadLocal :线程(并发)
*/
public class MyJdbcUtils {
private static DataSource dataSource = null ;
private static ThreadLocal<Connection> t1 = new ThreadLocal<Connection>() ;
//一个链接对象---相当线程
private MyJdbcUtils(){}
static{
try {
//创建一个属性集合类
Properties prop = new Properties() ;
//读取druid.properties的参数
InputStream inputStream = MyJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//加载属性集合列表中
prop.load(inputStream);
//通过工厂类
dataSource = DruidDataSourceFactory.createDataSource(prop);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取数据链接
public static Connection getCoonnection(){
//声明conn变量
Connection conn = null ;
try{
//获取连接对象
//先判断 ,如果当前conn 为null
if(conn==null){
//从连接池获取到
conn = dataSource.getConnection();
//一个连接相当一一个线程
//连接对象绑定ThreadLocal中
t1.set(conn);
}
return conn ;
}catch(Exception e){
e.printStackTrace();
}
return null ;
}
//获取数据源
public static DataSource getDataSource(){
return dataSource;
}
//释放资源
//提供关闭资源方法:针对DQL语句:查询获取结果集,关闭相关资源
public static void close(ResultSet rs, Statement stmt, Connection conn) throws SQLException {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
conn.close();
//解绑:从ThreadLocal (连接使用完毕,线程就执行完毕
t1.remove();
}
}
//针对DDL,DML操作:不需要ResultSet
public static void close(Statement stmt,Connection conn) throws SQLException {
close(null,stmt,conn);
}
//开启事务
public static void setAutoCommit(){
Connection conn = null ;
try {
conn = getCoonnection();
// //开启事务
conn.setAutoCommit(false); //取消自动提交
} catch (SQLException e) {
e.printStackTrace();
}
}
//如果事务的操作没有问题,提交事务并释放连接
public static void commitAndClose() throws SQLException {
Connection conn = getCoonnection();
//提交事务
conn.commit();
//释放连接
conn.close();
//解绑
t1.remove(); //线程(用户操作的时候,连接对象是完毕,线程执行完毕!)
}
//如果执行过程中出现问题,回滚事务
public static void rollbackAndClose() throws SQLException {
Connection conn = getCoonnection();
//事务回滚
conn.rollback();
//释放连接--归还到连接池
conn.close();
//解绑
t1.remove(); //线程(用户操作的时候,连接对象是完毕,线程执行完毕!)
}
public static void main(String[] args) {
Connection connection = MyJdbcUtils.getCoonnection();
System.out.println(connection);
DataSource dataSource = MyJdbcUtils.getDataSource();
System.out.println(dataSource);
}
}
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/* Druid:德鲁伊连接池
* 阿里提供的开源的!
*
* 基本使用步骤:
* 1)导入核心包:druid-1.0.9.jar
* 2)src防止druid.properties配置文件
* 3)创建DruidDataSrource---->工厂类DruidDataSourceFactory调用createDruidDataSource方法完成创建!
* 4)获取数据库连接对象
*/
public class DruidDataSourceDemo {
public static void main(String[] args) throws Exception {
//创建一个属性集合类
Properties prop =new Properties() ;
InputStream inputStream = DruidDataSourceDemo.class.getClassLoader().getResourceAsStream("druid.properties");
prop.load(inputStream);
System.out.println(prop);
// public static DataSource createDataSource(Properties properties)
DataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
System.out.println(dataSource);
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}