文章目录
JDBC
1.JDBC流程
JDBC: Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
JDBC的本质就是能够实现sun公司提供的java.sql包下的相关的接口的实现类
数据库厂商提供这一驱动jar包
使用java连接数据库过程:
1)在java项目添加额外的第三方的jar包
idea中 file----> project structure (ctrl+Alt+shift+s:默认快捷键_)---model---->denpendies---->添加---jar包 ---将指定路径拿过来
2)注册驱动
3)获取数据库的连接对象
4)准备静态sql语句
5)通过数据库连接对象创建执行对象Statement
6)执行更新操作
7)释放资源
public class JdbcDemo {
public static void main(String[] args) throws Exception {
//1)导包了
//2)注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ; //mysql8.0 的驱动实现类:com.mysql.cj.jdbc.Driver
//mysql8.0以前的驱动实现类:com.mysql.jdbc.Driver
//3)获取数据库的连接对象
//使用驱动管理类 DriverManager:用于管理一组JDBC驱动程序的基本服务。
//public static Connection getConnection(String url,String user,String password) throws SQLException
//参数1:url: 连接数据库的路径: 协议名称 + ip地址/域名 :3306/数据库名称 针对mysql server 8.0以前这样使用
//参数1:url: 连接数据库的路径: 协议名称 + ip地址/域名 :3306/数据库名称?参数1=值2&参数2=值2 针对mysql server 8.0使用
//?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
//参数2:用户名:root用户
//参数3:mysql连接的密码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb_01?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//4)准备sql语句
String sql = "insert into account(name,balance) values('赵又廷',1000)" ;
//5)通过数据库连接对象获取执行对象
//public Statement createStatement() ;用于将sql语句发送的数据库的执行器对象
Statement stmt = connection.createStatement();
//6)执行更新操作
//通用方法
//int executeUpdate(String sql) throws SQLException
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
//7)释放资源
stmt.close() ;
connection.close();
}
}
1)导包
2)注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ; //为了向下兼容 获取当前类的字节码文件对象
获取类的字节码文件对象com.mysql.cj.jdbc.Driver :Class类对象
源码
加载类的时候,就将静态代码块执行了,核心代码就是注册驱动
static {
try {
java.sql.DriverManager.registerDriver(new Driver());//注册驱动
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
java.sql.DriverManager
3)通过驱动管理了DrivarManager的getConnection(String url,String user,String password)
获取Connection
url:统一资源定位符 mysql8.0以后就必须带上了
jdbc:数据库协议://localhost:3306/ 数据库名称 ?参数(本地时区以及当前字符集&useSSL=false(不启用mysql连接认证)...
协议 域名或者ip:端口号/数据库名称?参数
user:用户名
password:密码
sun公司提供的 java.sql.Connection:接口
提供一些方法
public Statement createStatement() :创建执行对象Statement 接口
public PreparedStatement prepareStatement(String sql) :创建预编译对象的同时,发送参数化的sql
java.sql.Statement: 执行对象:将静态的sql发送到数据库中
每次发送的时都需要执行指定sql
通用的方法
int exeuteUpdate(String sql) :DDL语句:表的操作/以及DML语句insert into ,update,delete
ResultSet executeQuery(String sql):针对DQL语句:数据库的查询语句
select * from account where id = 值 ;
dml语句:数据操作语句
静态sql
insert into account(name,balance) values('值1',值2) ; (硬编码)
java.sql.prepearedStatement: 继承自 java.sql.Statement: 接口
预编译对象,发送的sql语句,
而且在通过连接Connection创建预编译对象的时候就已经将参数化的sql
insert into account(name,balance) values(?,?) ;
通用的方法
int exeuteUpdate() :DDL语句:表的操作/以及DML语句insert into ,update,delete
java.sql.ResultSet接口:数据库结果集的数据表
public boolean next():判断当前光标是否向前(有效数据行)移动(如果有数据,继续移动)
获取每一列的内容:根据每一个列的字段类型
通用的方法
XXX 变量名 = getXXX(列的名称/或者列的索引值) ; 方式1 :通用
getMetaData() ----ResultSetMetaData :数据表的元数据信息 方式2
2.操作
1)DDL操作
通过java.sql.Statment接口:针对DDL语句操作:建表语句
public class JdbcDemo {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建Connection对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql语句 DDL语句
String sql = "create table student(" +
"id int primary key auto_increment," +
" name varchar(20)," +
" gender varchar(10)," +
" email varchar(50) )" ;
//通过连接对象获取执行对象
stmt = conn.createStatement();
//发送sql语句到数据库中进行更新
// int exeuteUpdate(String sql) :DDL语句:表的操作/以及DML语句insert into ,update,delete
int count = stmt.executeUpdate(sql);
//0
System.out.println(count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
if(stmt!=null){ //释放执行对象
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){//释放连接对象
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
2)执行DML语句
Statment对象执行静态的sql语句----DML语句 insert into,delete,update
public class JdbcDemo2 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建Connection对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql语句 DML语句
String sql = "update student set gender = '女' where id = 3 " ;
//通过连接对象获取执行对象
stmt = conn.createStatement();
//发送sql语句到数据库中进行更新
// int exeuteUpdate(String sql) :DDL语句:表的操作/以及DML语句insert into ,update,delete
int count = stmt.executeUpdate(sql);
System.out.println(count);
System.out.println("修改成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
if(stmt!=null){ //释放执行对象
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){//释放连接对象
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
3)遍历SQL
ResultSet接口:一般都是select 查询语句查询的数据表的结果集
如何操作 select DQL语句
需求:将ee_2106这个数据库中的student表数据全部查询并遍历出来!
public class JdbcDemo3 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建数据库连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql
String sql = "select * from student" ;
//创建执行对象
stmt = conn.createStatement() ;
//执行sql语句
rs = stmt.executeQuery(sql);
//先判断
//第一次获取
if(rs.next()) {
//如果有下一行数据,那么就获取
//通用方法
//XXX getXXX(int columnIndex):列的索引值获取 内容 index从1 开始,第一列值就是1
//XXX getXXX(String columnIabel):列的名称获取 内容
int id = rs.getInt(1);
String name = rs.getString(2) ;
String gender = rs.getString(3) ;
String email = rs.getString(4) ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
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){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
工具类
封装jdbc操作的工具类
频繁的去操作数据库:CRUD:增删查改
每一条sql都去创建Connection对象
而且还需不断的去释放资源 Statment对象,Connection,ResultSet集合对象
/*jdbc.properties-----
url=jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
driverClass=com.mysql.cj.jdbc.Driver
user=root
password=123456
*/
public class JdbcUtils {
private static String url = null ;
private static String user = null ;
private static String password = null ;
private static String drivceClass = null ;
//构造方法私有化
private JdbcUtils(){}
//静态代码块
//JdbcUtils工具类一加载就执行静态代码块
static{
try {
//创建一个Properties属性列表
Properties prop = new Properties() ;
//读取src下面的jdbc.properties配置文件
//直接获取当前类的字节码文件对象,获取类加载,获取资源文件所在的输入流对象
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//将流中内容加载到属性列表中
prop.load(inputStream);
System.out.println(prop);//测试属性列表中的内容
//通过key获取value
url = prop.getProperty("url") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
drivceClass = prop.getProperty("driverClass") ;
//注册驱动
Class.forName(drivceClass) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//提供功能都是static
//通用的功能:获取数据库连接对象
public static Connection getConnection(){
Connection conn = null ;
try {
//通过驱动类管理类获取
conn = DriverManager.getConnection(url,user,password) ;
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭资源:
//DDL语句或者DML语句----->Statement对象和Connection
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
//关闭资源
//DQL语句---->ResultSet对象,Statement对象和Connection
public static void close(ResultSet rs,Statement stmt,Connection conn){
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){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
3.预编译对象PreparedStatement
1)是否能够防止sq1注入
Preparedstatement能够有效防止sq1注入(由于存在sq1语句字符串拼接造成sq1注入不安全)
statement:执行静态sq1语句,语句中就会在字符串拼接,造成sq1注入(不推荐)
2)是否高效(提高执行效率)
Preparedstatement因为操作的参数化的sq1语句,首先预编译---将sq7语句存储在预编译对象中,根据占位符号类型进行赋值setxxx(int parameterIndex ,实际参数(根据当前类型赋值))
直接通过预编译对执行sq7语句,发送到数据库中进行操作――(执行sq1效率高)
statement对象:每次将拼接好的sq1语句("硬编码")进行执行―(执行sq1效率低)
每次发送一个新的sq7到数据库中进行执行
executeupdate(string sq7)
executeQuery(string sq7)
预编译对象PreparedStatement 继承自Statment对象
操作步骤
1)注册驱动
2)获取数据库连接对象
3)准备参数化的sql 这些sql并非是静态sql语句
4)通过连接创建预编译对象并将参数化的sql语句保存在PreparedStatement对象中
5)给参数化的sql的数据进行赋值
6)执行更新/查询
7)释放资源
public class PerparedStatementDemo {
public static void main(String[] args) {
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
try {
//获取数据库的连接对象
conn = Utils.getConnection();
//准备sql语句:参数化的sql
//占位符号:?(英文符号)
// String sql = "insert into student(name,gender,email) values(?,?,?)" ;
String sql = "select * from student" ;
//通过连接对象获取预编译对象并将参数化的sql保存到该对象中
//PreparedStatement prepareStatement(String sql)
stmt = conn.prepareStatement(sql); //预编译的过程:对sql语句中占位符号进行描述
//参数赋值
//void setXXX(int parameterIndex,XXX num)
//举例:setString(第几个占位符号(占位符号的索引值:1开始),当前占位符的实际参数"hello" )
/* stmt.setString(1,"王桑") ;
stmt.setString(2,"男") ;
stmt.setString(3,"wangsang@163.com") ;*/
//执行
//ResultSet executeQuery() :执行查询操作:DQL语句
//int executeUpdate() 执行通用的更新操作:DDL/DML语句(insert into /update/delete)
// int count = stmt.executeUpdate();
// System.out.println("影响了"+count+"行");
//查询
rs = stmt.executeQuery();
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
String email = rs.getString("email");
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JdbcUtils.close(stmt,conn);
}
}
}
使用Statement对象模拟登录操作
键盘录入用户名和密码,判断是否登录成功
分析:
1)创建一个表 user(id,username,password)三个字段
2)封装一个功能isLogin(String username,String password)---->boolean
3)利用jdbc基本操作 查询user表即可
4)通过ResultSet的next()判断,如果查询到了 返回true,否则false!
问题:
Statement对象操作静态sql语句:硬编码而且由于如果存在sql语句字符串拼接
造成sql注入问题,用户名和密码不一致,依然登录成功,最不安全的行为!
select * from user where username='sdfs' and password = 'a 'OR 'a' ='a' 后面恒成立
Statement对象和PreparedStatement对比:
1)后者防止sql注入,前者存在sql注入(存在sql语句字符串拼接)
2)执行效率后者高于前者
前者效率低
每次获取Statement对象
executeUpdate(String sql)
executeQuery(String sql)
后者:
String sql = "select * from user where username=? and password = ?" ;
每次获取PreparedStatement对象的时候就已经sql保存在对象中进行预编译过程
赋值
executeUpdate()
executeQuery()
public class Statement_And_PreparedStatementTest {
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
//定义登录方法
public static boolean isLogin2(String username, String password) {
//获取数据库的连接对象
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
try {
conn = JdbcUtils.getConnection();
//准备sql :参数化sql
//通过用户和密码查询用户
String sql = "select * from user where username=? and password = ?" ;
System.out.println(sql);
//创建执行对象PreparedStatement预编译对象
stmt = conn.prepareStatement(sql) ;
//参数赋值
//在PerparedStatement对象中完成参数赋值过程
stmt.setString(1,username);
stmt.setString(2,password);
//执行查询
rs = stmt.executeQuery();
return rs.next() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,stmt,conn);
}
return false ;
}
//Statement对象
//定义登录方法
public static boolean isLogin(String username, String password) {
//获取数据库的连接对象
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
conn = JdbcUtils.getConnection();
//准备sql :静态sql
//通过用户和密码查询用户
String sql = "select * from user where username='"+username+"' and password = '"+password+"' " ;
System.out.println(sql);
//创建执行对象Statement对象
stmt = conn.createStatement();
//执行查询
rs = stmt.executeQuery(sql);
return rs.next() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,stmt,conn);
}
return false ;
}
}
4.连接池Druid
1.什么是连接池
是一种容器(集合),存储数据库连接对象;防止用户操作数据库的时候频繁,创建连接对象,而且当数据库连接Connection使用完毕,就释放close()---->消耗内存空间!
作用:提供操作数据库性能
当用户发送请求,需要连接数据库,频繁创建连接对象,还需要释放,这种情况耗时,消耗内存空间大
启用连接池,用户发送请求,直接通过连接池操作里面已经创建好的连接对象,获取当前线程中的某个Connection,然后直接去操作数据库,使用完毕连接对象之后,从当线程中进行解绑,回到连接池中!
提供固定的可重用的连接对象的容器
连接池的技术:
c3p0
dbcp
druid(推荐) 德鲁伊 阿里的开源项目
...
连接池本质就是需要实现sun公司提供的DataSource实现类(物理数据源代替 DriverManager)
1)导包 druid-1.1.10.jar
druid-1.1.10.source.jar:原码包(下载看DruidDataSource原码)
DruidDataSource 实现类
需要数据库驱动包:连接数据库mysql-connector-java-8.0.23.jar
2)准备好数据库连接池的配置文件
配置文件以.properties :
druid.properties
配置文件名称可以任意命名,但是必须在src目录下
3)读取配置文件
如何创建DataSource接口对象?
DruidDataSource-------> 此时会使用工厂模式
DruidDataSourceFactory工厂类
提供静态功能:创建数据源DruidDataSource
public static DataSource createDataSource(Properties properties) throws Exception
/*
1)导包 数据库驱动包/连接池的包
2)准备druid.properties
3)读取druid.properties配置文件
*/
public class DruidDataSourceDemo {
public static void main(String[] args) throws Exception {
//创建属性集合列表
Properties prop = new Properties() ;
//读druid.properties配置文件
InputStream inputStream = DruidDataSourceDemo.class.getClassLoader().getResourceAsStream("druid.properties");
//将druid.properties配置文件加载到属性列表中
prop.load(inputStream);
//通过Druid连接池提供的工厂类创建数据源对象DataSource 接口
//public static DataSource createDataSource(Properties properties) throws Exception
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//底层起始就是 子实现类对象DruidDataSoure
//Connection getConnection()
for(int x = 1; x <= 11 ; x ++){
Connection connection = dataSource.getConnection();
if(x == 5){
connection.close(); //并不是真正释放,而是归还到连接池中,等待下一次利用!
}
System.out.println(connection) ; //com.mysql.cj.jdbc.ConnectionImpl@2a17b7b6
}
// connection.close(); //并不是真正释放,而是归还到连接池中,等待下一次利用!
}
}
1)工具类
/**
* 工具类---->DataSource----->获取数据库的连接对象 Connection以及后期管理事务
* 获取连接对象----静态方法
* 关闭资源-----静态方法
*/
/*druid.properties:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb_01?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username=root
password=123456
#初始化连接数量
initialSize=5
#最大激活数量
maxActive=10
#最大等待时间(毫秒值,一旦超过3秒就报错了)
maxWait=3000
*/
public class DruidJdbcUtils {
//成员变量位置
private static DataSource ds ;
//为了保证线程安全:每一线程使用自己的Connection (张三/李四)
private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ; //提供线程的局部变量保存连接对象
//构造方法私有化
private DruidJdbcUtils(){}
//静态代码块
static{
try {
//读取数据库连接池的配置文件----->通过DruidDataSourceFactory工厂类创建DataSource
//创建一个属性集合列表
Properties prop = new Properties() ;
//读取druid.properties
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
getResourceAsStream("druid.properties");
//将资源文件所在的输入流加载列表中
prop.load(inputStream);
ds = DruidDataSourceFactory.createDataSource(prop); //底层子实现类:DruidDataSource
//System.out.println("数据源获取成功");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//提供静态方法:单独获取数据源
public static DataSource getDataSource(){
return ds ;
}
//获取连接对象Connection静态功能
public static Connection getConnection(){
//从ThreadLocal中获取局部变量的副本:Connection
/**
* public T get() :从线程中获取局部变量的副本!
*/
Connection conn = null ;
try {
conn = t1.get();
if(conn==null){
//如果空,需要从数据库的连接池中获取连接对象
conn = ds.getConnection();
//获取到之后,每一线程执行自己的Connection
//将获取到的连接对象 绑定到当前线程中
t1.set(conn);
}
//如果不为空,说明ThreadLocal线程中已经存在Connection
return conn ; //
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭(释放资源)资源
public static void close(ResultSet rs, Statement stmt,Connection conn) {
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){
try {
conn.close();
//关闭之后,归还到连接池中,需要从当前线程中解绑
t1.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close( Statement stmt,Connection conn) {
close(null,stmt,conn);
}
public static void rollback() {
try {
Connection connection = DruidJDBCTUtils.getConnection() ;
//调用回滚方法
connection.rollback();
//使用完毕,归还连接池中
connection.close();
//从当前线程中解绑
t.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2)三层架构思想
/*
admin管理员实体类
*/
public class Admin {
/* FieldTypeComment
id int NOT NULL
usernam evarchar(20) NULL
gender varchar(5) NULL
age int NULL
address varchar(50) NULL
phone varchar(11) NULL*/
private int id ;
private String username ;
private String gender ;
private int age ;
private String address ;
private String phone ;
public Admin() {
}
public Admin(int id, String username, String gender, int age, String address, String phone) {
this.id = id;
this.username = username;
this.gender = gender;
this.age = age;
this.address = address;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
/*
针对Admin业务接口层
*/
public interface AdminService {
/**
* 查询所有的Admin管理员实体
* @return 返回列表数据
*/
List<Admin> getAllAdmin() ;
/**
* 通过id 查询管理员
* @param id 管理员编号
* @return 返回实体对象
*/
Admin getAdmin(int id) ;
/**
* 查询总记录数
* @return
*/
int getCount() ;
}
/*
针对Admin的业务接口实现层
*/
public class AdminServiceImpl implements AdminService {
@Override
public List<Admin> getAllAdmin() {
//创建数据库访问接口对象AdminDao
AdminDao adminDao = new AdminDaoImpl() ;
List<Admin> list = adminDao.findAll();
return list;
}
/**
* 获取指定的管理员
* @param id 管理员编号
* @return
*/
@Override
public Admin getAdmin(int id) {
//调用dao层
AdminDao adminDao = new AdminDaoImpl() ;
Admin admin = adminDao.selectAdminById(id) ;
if(admin!=null){
return admin;
}else{
System.out.println("没有查找到管理员");
}
return null ;
}
@Override
public int getCount() {
//调用dao层
AdminDao adminDao = new AdminDaoImpl() ;
int count = adminDao.selectTotalCount() ;
return count;
}
}
/*
针对Admin的数据库访问接口层
*/
public interface AdminDao {
/**
* 数据库访问的查询所有的管理员列表
* @return 返回列表数据
*/
List<Admin> findAll() ;
/**
* 根据id编号查询指定的管理员
* @param id 编号
* @return 获取实体
*/
Admin selectAdminById(int id);
/**
* 查询总记录数
* @return
*/
int selectTotalCount();
}
/*
针对Admin的数据库访问接口实现层
*/
public class AdminDaoImpl implements AdminDao {
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
@Override
public List<Admin> findAll() {
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin" ;
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
rs = stmt.executeQuery() ;
//创建List
List<Admin> list = new ArrayList<>() ;
//声明admin变量 Admin类型的
Admin admin = null ;
while(rs.next()){
admin = new Admin() ;
int id = rs.getInt("id");
String username = rs.getString("username");
String gender = rs.getString("gender");
int age = rs.getInt("age");
String address = rs.getString("address");
String phone = rs.getString("phone");
//封装Admin实体
admin.setId(id);
admin.setUsername(username);
admin.setGender(gender);
admin.setAge(age);
admin.setAddress(address);
admin.setPhone(phone);
//添加到集合中
list.add(admin) ;
}
return list ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return null;
}
//查询单个实体
@Override
public Admin selectAdminById(int id) {
//获取数据库的连接对象
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin where id = ?" ;
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
//参数赋值
stmt.setInt(1,id);
//执行更新
rs = stmt.executeQuery() ;
Admin admin = null ;
while(rs.next()){
admin = new Admin() ;
int adminId = rs.getInt("id");
String username = rs.getString("username");
String gender = rs.getString("gender");
int age = rs.getInt("age");
String address = rs.getString("address");
String phone = rs.getString("phone");
//封装
admin.setId(adminId);
admin.setUsername(username);
admin.setGender(gender);
admin.setAge(age);
admin.setAddress(address);
admin.setPhone(phone);
}
return admin ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return null;
}
@Override
public int selectTotalCount() {
//获取数据库的连接对象
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin" ; //全部数据
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
//执行更新
rs = stmt.executeQuery() ;
//int getRow():ResultSet 获取行数 (第一行1,第二行2)
int countRow = 0 ;
while(rs.next()) {
countRow ++ ;
}
return countRow ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return 0 ;
}
}
public class MyTest {
/* public static void main(String[] args) {
//调用业务层Service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}*/
//测试查询功能所有
@Test
public void testFindAll(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}
//测试查询某个管理员
@Test
public void testfindById(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
Admin admin = adminService.getAdmin(2);
System.out.println(admin);
}
//测试查询总记录数
@Test
public void testSelectTotalCount(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
int totalCount = adminService.getCount();
System.out.println(totalCount);
}
}
5.测试
1.黑盒白盒
2.单元测试
提供junit的内置注解
@Test
提供单元测试方法(编写的测试用例,测试某个模块的功能(查询/添加/删除/修改))
@Before标记的方法
在执行@Test单元测试方法之前先执行 (初始化的操作)
@After标记的方法
在执行@Test单元测试方法之后执行(一般:资源的关闭)
注解本质---->接口
1)编写一个类
2)编写一个单元测试方法,不需要参数,也不需要返回值类型
public void testFindAll()
3)方法上加入注解@TestDemo
4)编写测试代码----- 调用serivce 业务代码,获取数据
public class TestDemo {
//测试查询功能
@Test
public void testFindAll(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}
@Before
public void init(){
System.out.println("初始化操作...");
}
@After
public void close(){
System.out.println("释放相关的系统资源");
}
@Test
public void testSub(){
//创建计算器类
Calculator calculator = new Calculator() ;
int result = calculator.sub(10, 5);
//断言进行测试
//assertArrayEquals:测试数组相关(操作多个数据)
//assertEquals(预期结果,功能性测试结果)
Assert.assertEquals(5,result);
}
}
/*
计算器类---开发人员开发好的
*/
public class Calculator {
public int sum(int a,int b){
return a + b ;
}
public int sub(int a, int b){//减法
return a + b ;
}
}
6.dbutils
apache提供开源工具类库 commons-dbutils :通用jdbc工具
将查询的结果或者更新操作进行封装 (PreparedStatement--->executeUpdate()/executeQuery()进行了封装)
1)导包 核心工具包
commons-dbutils-1.7.jar
依赖包 commons-logging:支持相关的
commons-collections:工具类中涉及其他的api
2)获取数据库的连接对象Connection
3)获取执行对象:通过物理数据源DataSource:java.sql.DataSource(sun公司提供一个接口)---->替代了DriverManager
QueryRunner
//基本使用
public class DbUtilsDemo {
public static void main(String[] args) throws SQLException {
//1)创建执行对象QueryRunner (执行对象)
// public QueryRunner(DataSource ds) { //数据源
// super(ds);
// }
//属于自动提交
QueryRunner queryRunner = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//需要给ee_2106的admin表 添加一条数据
//插入数据
String sql = "insert into admin(username,gender,age,address,phone) values(?,?,?,?,?)" ;
//执行通用方法:update()DML语句 ,query()DQL
// update(String sql,Object...parames):参数1sql 参数2:可变参数,可以使用多个实际参数
int count = queryRunner.update(sql, "王宝强", "男", 20, "西安市", "13566662222");
System.out.println(count);
//不需要关闭资源
}
}
eg:用户查询
/**
* 管理员类
* JavaBean是一种规范:
* 1)当前类是具体类
* 2)当前类中字段(成员变量)私有化
* 3)需要通过公共setXXX()/getXXX()方法
* 4)当前类可以实现序列化接口
*/
public class Admin implements Serializable {
private int id ;
private String username ;
private String gender ;
private int age ;
private String address ;
private String phone ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() { //getXXX() get()去掉 username 称为 当前类bean属性
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
pulic void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
/**
* @author Kuke
* @date 2021/8/19
*
* 针对Admin业务接口
*/
public interface AdminService {
/**
* 获取所有管理员列表
* @return 列表
*/
List<Admin> getAllAdmin() ;
/**
* 查询编号获取Admin实体
* @param id 编号
* @return 返回实体对象
*/
Admin getAdmin(int id) ;
/**
* 查询总记录
* @return
*/
long getTotal() ;
/**
* 根据id修改admin
* @param admin
* @return
*/
int update(Admin admin) ;
}
/**
* @author Kuke
* @date 2021/8/19
* 针对Admin的业务接口实现类
*/
public class AdminServiceImpl implements AdminService {
@Override
public List<Admin> getAllAdmin() {
//调用数据库访问接口
AdminDao adminDao = new AdminDaoImpl() ;
List<Admin> list = adminDao.findAll() ;
if(list!=null){
return list ;
}
return null ;
}
@Override
public Admin getAdmin(int id) {
//调用数据库访问接口
AdminDao adminDao = new AdminDaoImpl() ;
Admin admin = adminDao.findAdminById(id) ;
if(admin!=null){
return admin ;
}
return null;
}
@Override
public long getTotal() {
//调用数据库访问jiekou
AdminDao adminDao = new AdminDaoImpl() ;
long count = adminDao.selectTotalCount() ;
return count;
}
@Override
public int update(Admin admin) {
//1)修改管理员数据,需要通过id查询Admin
AdminDao adminDao = new AdminDaoImpl() ;
//通过编号查询Admin
Admin selectAdmin = adminDao.findAdminById(admin.getId());
if(selectAdmin !=null){
//存在
//进行修改
int count = adminDao.updateAdmin(admin) ;
return count ;
}
return 0;
}
public static void main(String[] args) {
AdminService adminService = new AdminServiceImpl() ;
Admin admin = new Admin() ;
admin.setId(3) ;
admin.setUsername("张三丰");
admin.setGender("男");
admin.setAge(20);
admin.setAddress("南窑国际");
admin.setPhone("13588889999");
int count = adminService.update(admin);
System.out.println(count);
}
}
/**
* @author Kuke
* @date 2021/8/19
* 针对Admin数据库访问接口
*/
public interface AdminDao {
/**
* 获取所有管理员列表
* @return 列表
*/
List<Admin> findAll();
/**
* 查询编号获取Admin实体
* @param id 编号
* @return 返回实体对象
*/
Admin findAdminById(int id);
/**
* 查询总记录
* @return
*/
long selectTotalCount();
/**
* 修改admin
* @param selectAdmin
* @return
*/
int updateAdmin(Admin selectAdmin);
}
/**
* @author Kuke
* @date 2021/8/19
* 针对Admin的数据库访问接口实现类
*/
public class AdminDaoImpl implements AdminDao {
@Override
public List<Admin> findAll() {
try {
//创建执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//准备sql语句
String sql = "select * from admin" ;
//执行查询
//query(String sql,ResuletSetHandler handler)
//参数1:sql
//参数2:结果集的处理
//子类:BeanListHandler<T> 将查询的多条记录封装到List集合中
//List<当前指定的javeBean实体>
// BeanListHandler<将查询的结果封装实体类型>(当前实体的类Class)
List<Admin> list = qr.query(sql, new BeanListHandler<Admin>(Admin.class));
return list ;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//通过id查询Admin实体
@Override
public Admin findAdminById(int id) {
try {
//创建执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from admin where id = ?" ;
//执行查询
//query(String sql,ResultSetHandler handler,Object...params)
//将查询的某一条记录封装到实体类(JavaBean)中,使用到类BeanHandler<T>
Admin admin = qr.query(sql, new BeanHandler<Admin>(Admin.class), id);
return admin;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//查询总记录数
@Override
public long selectTotalCount() {
//QueryRunner执行对象
try {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select count(id) from admin" ;
//查询一些单行单列的数据(总记录数),使用单类ScalerHandler<>
long count = (Long)qr.query(sql, new ScalarHandler<>());
return count ;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
//修改Admin
@Override
public int updateAdmin(Admin selectAdmin) {
try {
//QueryRunner
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "update admin set username=? ,gender=? ,age =? ,address =? ,phone =? where id= ?" ;
//更新操作
int count = qr.update(sql,
selectAdmin.getUsername(),
selectAdmin.getGender(),
selectAdmin.getAge(),
selectAdmin.getAddress(),
selectAdmin.getPhone(),
selectAdmin.getId());
System.out.println(count);
return count ;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
}
/**
* @author Kuke
* @date 2021/8/19
* 提供一些业务测试 (单元测试)
*/
public class DbutilsTest {
@Test
public void testFindAll(){
//调用业务层方法
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
for (Admin admin : list) {
System.out.println(admin);
}
}
@Test
public void testFindById(){
AdminService adminService = new AdminServiceImpl() ;
Admin admin = adminService.getAdmin(3);
System.out.println(admin);
}
@Test
public void testSelectTotalCount(){
AdminService adminService = new AdminServiceImpl() ;
long count = adminService.getTotal();
System.out.println(count);
}
@Test
public void testUpdateAdmin(){
AdminService adminService = new AdminServiceImpl() ;
//创建Admin
Admin admin = new Admin() ;
admin.setId(3) ;
admin.setUsername("张三丰2");
admin.setGender("男2");
admin.setAge(22);
admin.setAddress("南窑国际2");
admin.setPhone("13588889888");
int count = adminService.update(admin);
System.out.println(count);
}
}
7.事务
jdbc操作管理事务
事务:
一种机制,某个业务中多次调用dao完成多个sql同时执行,要么同时执行成功/要么同时执行失败,否则,就出现数据紊乱! 使用事务管理(JDBC方式操作)
用户发送请求,通过连接池获取Connection对象
Connection:管理事务的功能
void setAutoCommit(boolean autoCommit) throws SQLException
默认情况下,新创建的连接对象处于自动提交模式 参数为true,声明为false,禁用自动提交
需要收到提交sql
void rollback() throws SQLException:当前执行提交之前,如果sql发生异常,将撤销之前的所有操作
void commit() throws SQLException:如果执行过程中没有问题或者回滚了,都提交事务,将之前的所有操作永久保存!
/*
* 需求:mydb_01数据库中的account表
* zhangsan账户---- lisi账户 转账500
*
* 1)获取连接对象
* 2)准备sql语句
* 两个update的sql
* zhagnsan -500
* lisi+ 500
* 3)分别执行
* 4)释放资源
*/
public class JdbcTransactionDemo {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement stmt1 = null;
PreparedStatement stmt2 = null;
try {
//通过DruidJdbcUtils获取连接对象
connection = DruidJdbcUtils.getConnection();
//开启事务---将自动提交禁用调用,参数为false,手动提交
connection.setAutoCommit(false);
//准备sql语句
String sql1 = "update account set balance = balance - ? where id = ?" ;
//创建预编译对象对sql1进行预编译
stmt1 = connection.prepareStatement(sql1);
//参数赋值
stmt1.setInt(1,500);
stmt1.setInt(2,1);
//执行更新
stmt1.executeUpdate() ;
//程序出问题了
// int i = 10 /0 ;
String sql2 = "update account set balance = balance + ? where id = ? " ;
//创建预编译对象对sql2进行预编译
stmt2 = connection.prepareStatement(sql2);
//参数赋值
stmt2.setInt(1,500);
stmt2.setInt(2,2);
//执行更新
stmt2.executeUpdate() ;
//如果没有问题,正常提交
connection.commit();
System.out.println("转账成功...");
} catch (SQLException e) {
//处理异常: 直接事务回滚
//有异常,执行catch语句,就回滚
try {
System.out.println("程序出问题了...");
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
//e.printStackTrace();
}
//释放资源
DruidJdbcUtils.close(stmt1,connection);
DruidJdbcUtils.close(stmt2,connection);
}
}