一.JDBC概述
概念作用:
JDBC (Java DataBase Connectivity) java连接数据库 技术。
JDBC可以实现java语言对数据库表数据的增删改查操作。Java负责后台程序业务逻辑编写的,sql负责数据库增删改查的操作的,我们不能直接使用java去操作sql语言。在这个过程中我们需要一个连接的桥梁或者叫纽带,JDBC就是扮演了这个连接的角色。
JDBC技术可以实现java和多种数据库的连接:mysql sqlserver oracle
下载
JDBC由第三方团队开发,提供给开发者使用,我们做为开发人员只需要掌握其使用方法及常用API即可,至于技术的升级和维护不需要我们去考虑。JDBC是以jar包的形式提供给我们使用,所以我们使用之前需要先下载jar包(封装的java类 .jar文件)。
下载地址:
https://downloads.mysql.com/archives/c-j/
解压:
mysql-connector-java-5.1.40-bin.jar就是我们需要的JDBC驱动jar包。
JDBC连接步骤
① 创建java项目,导入下的JDBC驱动包
② 加载JDBC驱动包到程序
③ 创建JDBC连接对象Connection
④ 创建sql的执行对象
⑤ 执行目标sql语句
⑥ 处理执行sql结果返回值
⑦ 关闭连接,释放资源
JDBC入门案例
入门案例实现
1、创建java项目,导入JDBC驱动包
2、编写入门案例代码
public class JDBCTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载JDBC驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
String url="jdbc:mysql://localhost:3306/mysql0202";//连接的目标数据库
String user="root";//mysql登录账号
String password="root";//mysql登录密码
Connection connection=DriverManager.getConnection(url, user, password);
//3.创建sql执行对象
Statement statement=connection.createStatement();
//4.执行目标sql语句
String sql="INSERT INTO students (sname)VALUES(\"张三丰\");";
int row=statement.executeUpdate(sql);
//5.处理执行sql的结果
System.out.println(row);
//6.关闭连接对象,释放资源
statement.close();
connection.close();
}
}
入门案例参数说明
以上案例中使用的API都来自于我们的jdk文档中。
//1.加载JDBC驱动:反射技术加载类字节码对象
Class.forName(“com.mysql.jdbc.Driver”);//使用反射将编译后的.class文件加载到内存中,jvm就可以执行这个文件
//2.创建连接对象
//jdbc:mysql使用jdbc连接mysql数据库
//localhost=127.0.0.1本机回环地址
//3306mysql默认端口号
//mysql0202目标数据库名称
String url=“jdbc:mysql://localhost:3306/mysql0202”;//连接的目标数据库
String user=“root”;//mysql登录账号
String password=“root”;//mysql登录密码
//DriverManager是JDBC驱动的管理对象,可以将驱动引入到程序中加载
//getConnection(url, user, password);创建连接对象的方法
//Connection连接java代码和mysql数据库的一个管理对象
Connection connection=DriverManager.getConnection(url, user, password);
//3.创建sql执行对象:执行sql语句的对象
//Statement对象中提供了对数据库表增删改查的API
//增删改:int num=executeUpdate(String sql);
//查询:ResultSet rs=executeQuery(String sql);
Statement statement=connection.createStatement();
//4.执行目标sql语句
String sql=“INSERT INTO students (sname)VALUES(“张三丰”);”;
//row表示影响数据库表的行数
int row=statement.executeUpdate(sql);
//5.处理执行sql的结果
System.out.println(row);
//6.关闭连接对象,释放资源
statement.close();
connection.close();
注意事项:
1、我们的对象全部在java.sql包下面
2、需要我们掌握的核心的JDBC对象
连接对象:Connection
sql执行器对象:
执行sql增删改查的方法
查询的返回的结果集对象:里面封装了查询的表中的所有数据
二.单元测试
单元测试:
功能和main函数类似,也是对代码段进行测试使用,但是一个java文件中可以设置多个单元测试的方法。这些方法都是相互独立运行的。
单元测试添加
1、eclipse设置添加
2、代码中添加注解
单元测试使用:代码调试
```java
/**
* 单元测试
* @author admin
*
*/
public class JDBCDemo1 {
/**
* 修改学生信息
*/
@Test
public void student_update() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql0202",
"root","root");
Statement statement = connection.createStatement();
int row = statement.executeUpdate("UPDATE students SET sname=\"关羽\" WHERE sid=4");
System.out.println(row);
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除学生信息
*/
@Test
public void student_delete() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql0202",
"root","root");
Statement statement = connection.createStatement();
int row = statement.executeUpdate("DELETE FROM students WHERE sid=4");
System.out.println(row);
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 查询所有学生信息
*/
@Test
public void student_show() {
try {
Class.forName("com.mysql.jdbc.Driver");
//localhost:3360当连接的是本地电脑mysql 3306端口号没有改变 可以省略不写
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0202","root","root");
Statement statement = connection.createStatement();
//查询返回的结果集是一个set集合:学生数据存在set集合中
ResultSet rs = statement.executeQuery("SELECT * FROM students");
//遍历集合
while(rs.next()) {//每次循环从表中获取一行学生数据
/**
* ResultSet对象中提供了获取数据的方法:
* getXXX()根据数据库表字段的类型提供了相应的不同数据类型获取方法
* getInt()
* getString():getString(1)获取字符串类型的字段,通过字段的索引来获取
* getString(sname)通过字段名称获取
* getObject()
* getDate()
*/
//获取学生的编号
//int sid = rs.getInt("sid");
//获取学生的姓名
//String sname = rs.getString("sname");
//推荐使用getObject()
Object sid = rs.getObject("sid");
Object sname = rs.getObject("sname");
System.out.println(sid+"===="+sname);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Sql注入
1.登录功能实现
需求:
在客户端输入账号和密码,进行登录的操作,如果账号密码正确则登录成功,否则登录失败。
需要sql:
SELECT * FROM users WHERE username=“lisi” AND userpwd=“123456”;
代码示例:
/**
* 登录测试
*/
@Test
public void user_login() {
//创建输入的函数
Scanner sc=new Scanner(System.in);
System.out.println("请输入账号:");
String username = sc.nextLine();
System.out.println("输入密码:");
String userpwd = sc.nextLine();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
Statement statement = connection.createStatement();
String sql="SELECT * FROM users WHERE username='"+username+"' AND userpwd='"+userpwd+"'";
System.out.println(sql);
ResultSet rs = statement.executeQuery(sql);
if (rs.next()) {
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
} catch (Exception e) {
e.printStackTrace();
}
}
2.Sql注入问题
以上是登录的时候,使用特殊字符实现的sql注入效果。
Sql注入概念:
在客户端输入一些特殊的字符,来对数据库服务器进行掩饰,从而达到一些非法的操作。这个操作是非常不安全的,我们在开发的时候是需要避免掉的。
Sql注入的解决方案:
我们不使用statement对象,使用预编译对象PreparedStatement对象。
查询预编译对象:
预编译对象PreparedStatement和执行器Statement的关系:
1、PreparedStatement是Statement的子接口
2、statement是执行sql的时候进行sql的 编译,也就是静态的执行效果;PreparedStatement对象是一个预编译对象,在执行sql之前已经编译完成。并且在后期可以多次的执行编译后的sql。
3、Statement执行sql的时候,传入的参数参与了sql的编译过程;PreparedStatement执行sql的时候已经编译完成,传入的参数不会参与编译过程
Sql预编译对象使用
1.Sql注入问题解决
/**
* 解决sql注入
*/
@Test
public void user_login1() {
//创建输入的函数
Scanner sc=new Scanner(System.in);
System.out.println("请输入账号:");
String username = sc.nextLine();
System.out.println("输入密码:");
String userpwd = sc.nextLine();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
String sql="SELECT * FROM users WHERE username=? AND userpwd=?";
//预编译:创建sql执行器对象的时候对sql进行编译
PreparedStatement ps = connection.prepareStatement(sql);
/**
* 预编译机制使用了占位符操作:
* ?代码占位符,在编译的时候替换未知的变量值
*
*/
//sql执行之前讲占位符替换成具体变量值
ps.setObject(1, username);
ps.setObject(2, userpwd);
//SELECT * FROM users WHERE username=? AND userpwd=?
System.out.println(sql);
//执行sql的时候不需要编译sql
ResultSet rs = ps.executeQuery();
if (rs.next()) {
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
} catch (Exception e) {
e.printStackTrace();
}
}
小结:
1、预编译对象,使用了占位符机制在创预编译对象的时候将sql进行编译。
2、传入参数的时候,使用占位符替换变量值,
3、执行sql的时候,sql已经完成了编译过程,所以传入的参数就不会参与编译过程,从而避免sql注入问题。
2.增删改查实现
需求:使用预编译对象实现用户表CRUD操作。
代码示例:
/**
* 查询用户信息
*/
@Test
public void user_show() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
String sql="SELECT * FROM users";
PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
System.out.println("账号:"+rs.getObject("username")+"\t密码:"+rs.getObject("userpwd"));
}
rs.close();
ps.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除用户信息
*/
@Test
public void user_delete() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
String sql="DELETE FROM users WHERE uid=?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1, 4);
int row = ps.executeUpdate();
System.out.println(row);
ps.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 修改用户信息
*/
@Test
public void user_update() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
String sql="UPDATE users SET username=? ,userpwd=? WHERE uid=?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1, "李时珍");
ps.setObject(2, "789");
ps.setObject(3, 4);
int row = ps.executeUpdate();
System.out.println(row);
ps.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增加一个用户
*/
@Test
public void user_insert() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
//创建增加的sql
String sql="INSERT INTO users(username,userpwd)VALUES(?,?)";
//创建预编译对象
PreparedStatement ps = connection.prepareStatement(sql);
//替换占位符的值
ps.setObject(1, "李四");
ps.setObject(2, "456");
//执行sql
int row = ps.executeUpdate();
System.out.println(row);
ps.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
四.封装JDBC工具类
1.JDBC工具类封装
需求说明:
之前的CRUD(增删改查)代码中有一些重复的代码,我们可以将他们抽取出来封装成工具类。
封装的思想可以简化代码开发,提高代码的复用性,提高开发的效率。
补充知识点:
Propertis类实现了Map接口,也就是可以使用map接口的API。
获取数据:String getProperty(String key, String defaultValue)
存储数据:Object setProperty(String key, String value)
加载文件中的数据:load()
封装的思路:
1、创建配置文件:jdbc.propertie
2、编写JDBC工具类:JDBCTool
代码示例:
Jdbc.properties
创建一个properties文件,里面写以下内容:
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql:///mysql0203
mysql.user=root
mysql.password=root
工具类:JDBCTool
/**
* JDBC工具类
* @author admin
*
*/
public class JDBCTool {
//定义一个连接对象
private static Connection connection=null;
/**
* 加载配置文件中的数据,创建连接对象
*/
static {
try {
//创建加载配置文件的propertis对象
Properties properties=new Properties();
//加载配置
properties.load(new FileInputStream(new File("src/jdbc.properties")));
//获取配置文件中的参数
String dirver = properties.getProperty("mysql.driver");
String url = properties.getProperty("mysql.url");
String user = properties.getProperty("mysql.user");
String password = properties.getProperty("mysql.password");
//加载JDBC驱动
Class.forName(dirver);
//创建连接对象
connection = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接对象
*/
public static Connection getConnection() {
return connection;
}
/**
* 关闭查询对象释放资源
*/
public static void closeQuery(Connection connection,
Statement statement,ResultSet resultSet) {
try {
if (resultSet!=null) {
resultSet.close();
}
if (statement!=null) {
statement.close();
}
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭增删改对象释放资源
*/
public static void closeUpdate(Connection connection,
Statement statement) {
try {
if (statement!=null) {
statement.close();
}
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2.优化增删改查
/**
* 增加用户
*/
@Test
public void user_insert() {
try {
//使用工具类创建连接对象
Connection connection = JDBCTool.getConnection();
//创建预编译对象
PreparedStatement ps = connection.prepareStatement("INSERT INTO users(username,userpwd)VALUES(?,?)");
ps.setObject(1, "翠花");
ps.setObject(2, "123456");
int row = ps.executeUpdate();
System.out.println(row);
//关闭对象
JDBCTool.closeUpdate(connection, ps);
} catch (SQLException e) {
e.printStackTrace();
}
}
五、数据库连接池
5.1连接池概念原理
多线程:线程池?比如:共享单车 共享充电宝
目前操作数据库的图示:
这样的操作存在的问题:
1、数据库连接是一种关键的有限的昂贵的资源,传统数据库连接每发出一个请求都要创建一个 连接对象,使用完直接关闭不能重复利用;
2、关闭资源需要手动完成,一旦忘记会造成内存溢出;(内存泄漏和内存溢出)
3、请求过于频繁的时候,创建连接极其消耗内存;而且一旦高并发访问数据库,有可能会
造成系统崩溃。
解决方式:
使用连接池,连接池全称是 Database Connection Pool。
原理:
1、数据库连接池负责分配、管理和释放数据库连接,它的核心思想就是连接复用,
2、通过建立一 个数据库连接池,这个池中有若干个连接对象,当用户想要连接数据库,就要先从连接池中获取连接对象,然后操作数据库。
3、一旦连接池中的连接对象被用完了,判断连接对象的个数是否已达上限,如果没有可以再创建新的连接对象,
4、如果已达上限,用户必须处于等待状态, 等待其他用户释放连接对象,直到连接池中有被释放的连接对象了,这时候等待的用户才能获取连接对象,从而操作数据库。
5、这样就可以使连接池中的连接得到高效、安全的复用,避免了数据库连接频繁创建、关闭的开销。这项技术明显提高对数据库操作的性能。
连接池的优势:
(1)程序启动时提前创建好连接,不用用户请求时创建,给服务器减轻压力;
(2)连接关闭的时候不会直接销毁 connection,这样能够重复利用;
(3)如果超过设定的连接数量但是还没有达到最大值,那么可以再创建;
(4)如果空闲了,会默认销毁(释放)一些连接,让系统性能达到最优;
面试题:
内存泄漏和内存溢出的区别?(面试题)
内存溢出(out of memory):指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory,简单通俗理解就是内存不够用了,比如给了你一个储存int类型数据的内存空间,你缺用来存了long类型的数据,结果就会导致内存不够用,就会报错OOM(内存溢出)。
内存泄露(memory leak):指程序在申请内存后,无法释放已申请的内存空间,内存泄露堆积会导致内存被占光。借用别人的比喻就是:比如有10张纸,本来一人一张,画完自己擦了还回去,别人可以继续画,现在有个坏蛋要了纸不擦不还,然后还跑了找不到人了,如此就只剩下9张纸给别人用了,这样的人多起来后,最后大家一张纸都没有了。
两者关系:内存泄露 → 剩余内存不足 → 后续申请不到足够内存 →内存溢出memory leak 最终会导致 out of memory。
线程池和连接池的区别?(面试题)
连接池:
1、连接池是面向数据库连接的
2、连接池是为了优化数据库连接资源
3、连接池有点类似在客户端做优化
线程池:
1.、线程池是面向后台程序的
2、线程池是是为了提高内存和CPU效率
3、线程池有点类似于在服务端做优化
5.2自定义连接池
连接池技术可以分为两大类:
1)自定义连接池:自己或者团队需要的时候可以自己封装连接池
2)第三方连接池:目前市面上比较流行的连接池技术(推荐使用)
自定义连接池思路:
1、创建一个保存连接对象的容器或者叫池子
2、创建获取连接对象的方法
3、创建归还连接对象的方法
4、测试连接池
代码示例:
public class MyDataBasePool {
//1、创建一个保存连接对象的容器或者叫池子
private static List<Connection> poolList=new ArrayList<Connection>();
//定义初始化连接数量
private static int num=10;
//创建若干连接对象,存储到连接池集合对象中
static {
for (int i = 0; i <num; i++) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///mysql0203", "root", "root");
//将连接对象存储到连接池集合中
poolList.add(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//2、创建获取连接对象的方法
public static Connection getConnection() {
//从集合中获取一个连接对象
Connection connection = poolList.get(0);
System.out.println(connection);
//将集合的元素移除
poolList.remove(0);
return connection;
}
//3、创建归还连接对象的方法
public static void returnConnection(ResultSet resultSet,
Statement statement,Connection connection) {
try {
if (resultSet!=null) {
resultSet.close();
}
if (statement!=null) {
statement.close();
}
if (connection!=null) {
System.out.println(connection);
//将连接对象放回集合中
poolList.add(connection);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
CRUD测试
/**
* 自定义连接池测试
*/
@Test
public void user_insert() {
//创建连接对象
Connection connection = MyDataBasePool.getConnection();
String sql="INSERT INTO users(username,userpwd)VALUES(?,?)";
try {
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1, "xiaohei");
ps.setObject(2, "123456");
int row = ps.executeUpdate();
System.out.println(row);
//归还连接
MyDataBasePool.returnConnection(null, ps, connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
5.3第三方连接池
1、概述
在 Java 中开源的常用的数据库连接池有以下几种 :
1)DBCP
DBCP 是一个依赖 Jakarta commons-pool 对象池机制的数据库连接池.DBCP 可以直接的在应用程序中使用,Tomcat 的数据源使用的就是 DBCP。
2)c3p0 (推荐)
c3p0 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,包括了实
现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象。
3)Druid
阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一 个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。支持所有 JDBC 兼容的数据 库,包括 Oracle、MySql、Derby、Postgresql、SQL
2、连接池常见的配置
3、第三方连接池使用-DBCP
Dbcp连接池使用:
提供的资料
使用步骤:
1、导入jar到项目中
2、导入配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///mysql0203
username=root
password=root
3、编写工具类
/**
* DBCP连接池工具类
* @author admin
*
*/
public class DBCPPool {
//定义一个连接对象变量
private static Connection connection=null;
/**
* 加载dbcp.properties配置文件获取里面的参数
*/
static {
try {
Properties properties=new Properties();
properties.load(new FileInputStream(new File("src/dbcp.properties")));
//创建数据源对象
DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
//创建连接对象
connection = dataSource.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接对象的方法
*/
public static Connection getConnection() {
return connection;
}
}
4、测试CRUD
/**
* dbcp连接池测试
*/
@Test
public void user_insert_dbcp() {
//创建连接对象
Connection connection = DBCPPool.getConnection();
String sql="INSERT INTO users(username,userpwd)VALUES(?,?)";
try {
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1, "cuihua");
ps.setObject(2, "111111");
int row = ps.executeUpdate();
System.out.println(row);
} catch (SQLException e) {
e.printStackTrace();
}
}
4、第三方连接-c3p0
1、提供的资料
3、使用步骤
① 导入jar包
② 导入配置文件并修改
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///mysql0203?useUnicode=true&characterEncoding=utf-8
c3p0.user=root
c3p0.password=root
③ 封装工具类
/**
* 1.c3p0连接池使用注意事项:
* 配置文件必须放在src目录下
* 配置文件中的key不能改变
*/
//创建连接对象
public static Connection getConnection() {
//创建数据源对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//创建连接对象
Connection connection=null;
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
④ 测试
/**
* c3p0连接池测试
*/
@Test
public void user_insert_c3p0() {
//创建连接对象
Connection connection = C3p0Pool.getConnection();
String sql="INSERT INTO users(username,userpwd)VALUES(?,?)";
try {
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1, "关羽");
ps.setObject(2, "111111");
int row = ps.executeUpdate();
System.out.println(row);
} catch (SQLException e) {
e.printStackTrace();
}
}
六.DBUTils工具类
1、概述
概念:
DBUTIls工具类,在原生的JDBC基础是进行二次封装的第三方工具类。
下载:
http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi
下载后的资料:
DBUTils工具类的核心API简介:
1、DBUTIls类:关闭连接对象
2、QueryRunner类:执行数据库的增删改查操作,这个类中提供了update()执行增删改操作,提供了query()方法执行查询操作。
3、ResultSetHandler接口:查询返回的结果集对象。将resultSet对象进行了二次的封装,提供了更加简介的查询结果对象。
2、DML操作实现
1)导入jar包
2)代码示例
dbutils+c3p0推荐使用的JDBC操作
/**
* 修改用户
*
*/
@Test
public void user_update() {
try {
//1.创建queryRunner:需要数据源对象
QueryRunner queryRunner=new QueryRunner(new ComboPooledDataSource());
//2执行sql
String sql="UPDATE users SET username=? ,userpwd=? WHERE uid=?";
int row = queryRunner.update(sql, "张三丰","456789",10);
System.out.println(row);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 增加用户
*/
@Test
public void user_insert() {
//1.创建QueryRunner对象:作用就相当于我们的statement和preparedStatement对象
/**
* 1、使用无参构造创建的对象:后面执行增删改查的操作时候需要携带connection
* 2、使用有参构造创建对象:构造函数中需要数据源对象,执行增删改查的时候不需要携带connection
*/
QueryRunner queryRunner=new QueryRunner();
//2执行目标sql
/**
* queryrunner提供了增删改的方法:update()当使用的queryrunner对象是无参构造创建的时候需要携带connection
* 查询方法:query()
*/
Connection connection = C3p0Pool.getConnection();
String sql="INSERT INTO users(username,userpwd)VALUES(?,?)";
try {
// Object... params可变参数:0或者多个参数列表
int row=queryRunner.update(connection,sql,"李四","789789");
//3.处理返回的结果
System.out.println(row);
} catch (SQLException e) {
e.printStackTrace();
}
}
3、DQL操作实现
DBUTIls封装的返回结果集ResultSetHandler有以下几种常用的实现类:
目前需要我们掌握的实现类:
1、BeanHandler 将查询的结果封装到一个javaBean对象中。通过返回的是一个结果对象。每个结果就是数据库表的一行数据。
2、BeanListHandler:将返回的结果封装到javaBean对象中然后在将对象封装到集合中,通常返回的是一个对象的结果集合。也就是对应的是数据库表的多行数据。
3、ScalarHandler:返回的是具体的一个整数,通常用在聚合查询中
知识点补充:javaBean
1)javaBean就是一个java类,类中所有的属性私有化,有set/get方法
2)一个javaBean类对应数据库表的一张表
3)一个javaBean实例化对象对应表的一行数据
4)JavaBean属性名称对应数据库表的字段名称
5)JavaBean属性的数据类型和数据表的字段类型对应
代码示例:
/**
* 查询所有用户信息
*/
@Test
public void user_all() {
try {
QueryRunner queryRunner=new QueryRunner(new ComboPooledDataSource());
String sql="SELECT * FROM users";
List<Users> list = queryRunner.query(sql,
new BeanListHandler<Users>(Users.class));
for (Users users : list) {
System.out.println(users);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 查询id=9的用户信息
*/
@Test
public void user_getUser() {
try {
QueryRunner queryRunner=new QueryRunner(new ComboPooledDataSource());
String sql="SELECT * FROM users WHERE uid=?";
//List<Integer> list=new ArrayList<Integer>();
//new BeanHandler<T>(type)相当于ResultSetHandler rs=new BeanHandler();
//T数据表对应的java实体类类名type实体类的字节码对象
Users users = queryRunner.query(sql, new BeanHandler<Users>(Users.class), 9);
System.out.println(users);
} catch (SQLException e) {
e.printStackTrace();
}
}
用户实体类:
public class Users {
//属性名称类型必须和用户表字段名称类型一致
private Integer uid;
private String username;
private String userpwd;
public Users(Integer uid, String username, String userpwd) {
super();
this.uid = uid;
this.username = username;
this.userpwd = userpwd;
}
//DBUTIls必须满足实体类中有无参构造
public Users() {
super();
// TODO Auto-generated constructor stub
}
//get/set方法
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
@Override
public String toString() {
return "Users [uid=" + uid + ", username=" + username + ", userpwd=" + userpwd + "]";
}
}
以上是javaJDBC及CURD知识学习的一些总结归纳,供自己复习巩固使用的,有需要学习的小伙伴也可以看一看,也可以给出一些建议或者出错的地方也可以告诉我。