卡1
JDBC概述
数据持久化
1.持久化:将内存中的数据存储在持久化存储中。
设备内部(磁盘等)
2.持久化的主要用途是将内存中的数据存储在关系数据库中。
但是,您也可以将其保存到磁盘文件或XML 数据文件。
三大Java平台
海我E
什么是JDBC?
JDBC(Java 数据库连接) Java 数据库连接
是的
JavaEE平台技术规范
定义了用于连接数据库并以Java 语言执行SQL 语句的标准API。
可以提供对多个关系数据库的集成访问
什么是数据库驱动程序
数据库驱动程序是直接操作数据库的程序。
每个数据产品都有不同的数据库驱动程序名称。
程序必须依赖数据库驱动程序来完成数据库操作。
访问Java数据库技术
基于JDBC 标准访问数据库
使用Hibernate、Mybatis等第三方ORM框架访问数据库。
驱动程序接口
1.
驱动程序接口
Driver接口的作用是定义数据库驱动对象必须具备的一些功能。
力量。例如,与数据库建立连接。
这个接口是提供给数据库厂商使用的,大家都支持。
所有使用Java语言连接的数据库都实现了这个接口,并且调用了实现这个接口的类。
数据库驱动类
2.
驱动管理类
DriverManager是驱动管理器,负责管理数据库驱动。
的。当您注册驱动程序时,注册列表将保存在DriverManager 中。
中间。可以创建DriverManager
应用程序和数据库之间建立连接。返回连接接口的类型。
数据库连接对象
getConnection(字符串jdbcUrl,字符串用户,字符串
密码)
该方法访问数据库URL、用户和密码并返回相应的数据。
数据库连接对象。
`1.JDBC URL
连接数据库时,用于连接指定的数据库标识符。在网址中
包含数据库
类型、地址、端口、库名称和其他信息。不同的
品牌数据库连接URL不同
1. 连接到您的MySQL 数据库。
连接器
=
司机经理
。
获得连接
(
\’
jdbc:
我的
ql: //主机:端口/数据库\’
,
\’用户\’
,
\’密码\’
); 输入主机端口数据库路径
2. 连接到您的Oracle 数据库。
连接器
=type关键字主机IP地址端口链接地址
司机经理
。
获得连接
(
\’jdbc:ora
cle:thin:@host:port:database\’
,
\’用户\’
,
\’密码\’
);
3.连接接口
Connection是数据库连接(会话)对象。对数据库的所有操作
所有的操作都是基于这个连接,并且可以通过这个对象来进行。
SQL语句及返回结果
一般方法
1.createStatement()
创建一个Statement接口类型的对象,将SQL发送到数据库。
2.准备语句(SQL)
创建一个PrepareSatement接口类型,将预编译的SQL发送到数据库
目的。
3.setAutoCommit(布尔自动提交)
设置是否自动提交事务。
4.提交()
在链接上提交交易。
5. 回滚()
回滚此链接上的事务。
4. 报表接口
用于执行静态SQL 语句并返回生成结果的对象。 经过
创建createStatement是为了发送简单的SQL语句(不支持动态语句)。
(有状态绑定)(参数必须绑定,因为不能使用占位符来替换它们)。
一般方法
1.执行(字符串SQL)
执行参数中的SQL,返回是否有结果集。
2.executeQuery(字符串SQL)
执行select 语句并返回ResultSet 结果集。
3.executeUpdate(字符串SQL)
执行插入/更新/删除操作并返回更新的行数。
4.addBatch(字符串SQL)
将多个SQL 语句放入一个批处理中。
5. 执行批处理()
将一批SQL语句发送到数据库执行。
5.PreparedStatement接口
继承自preparedStatement创建的Statement接口,用于发布。
提交带有一个或多个参数的SQL 语句。准备语句对象
由于它实现了动态参数绑定,因此它比Statement 对象更高效。
我通常使用以下内容,因为它可以防止SQL 注入:
准备好的声明。
一般方法
1.addBatch()
将当前SQL 语句添加到批处理中。
2.执行()
执行当前SQL并返回布尔值。
3.执行更新()
执行插入/更新/删除操作并返回更新的行数。
4.执行查询()
执行当前查询并返回结果集对象。
5.setDate(int参数索引,日期x)
将java.sql.Date 值绑定到当前SQL 语句中的指定位置。
6.setDouble(int 参数索引, double x)
将双精度值绑定到当前SQL 语句中的指定位置。
7.setFloat(int 参数索引, float x)
将浮点值绑定到当前SQL 语句中的指定位置。
8.setInt(int 参数索引, int x)
将int 值绑定到当前SQL 语句中的指定位置。
9.setString(int参数索引,字符串x)
将字符串值绑定到当前SQL 语句中的指定位置。
6.ResultSet接口
ResultSet用于临时存储数据库查询操作得到的结果集。
一般方法
1.getString(int索引),getString(字符串列名)
检索数据库中的数据对象,例如varchar 和char 类型。
2.getFloat(int索引)、getFloat(String列名)
获取数据库中的Float 数据对象。
3.getDate(int索引),getDate(String列名)
获取数据库中日期类型的数据。
4.getBoolean(int index), getBoolean(String 列名)
获取数据库中的布尔数据。
5.getObject(int索引),getObject(String列名)
获取数据库中的任何类型的数据。
JDBC创建步骤
获得连接
环境:
数据库Mysql5.7
数据库驱动程序版本5.1.48
数据库名称itbz
准备:
创建一个新的JavaProject 项目
添加数据库驱动jar包
添加数据库驱动jar包
获取数据库连接对象
下载数据库驱动
MySQL : 下载MySQL Connector/J(存档版本)
获取数据库连接
老师,测试数据库连接时出现这个错误是什么意思?
解决了:
字符串URL=\’jdbc:mysql: //localhost:3306/itbz
?useSSL=false\’;
问题分析:
SSL 有什么用?
SSL 全称(安全套接字层安全套接字协议)。外部连接mysql时,如果版本低于5.7则不需要添加useSSL。如果您的版本大于5.7,则必须添加useSSL。默认为false。
useSSL 设置为false 和true 的区别如下:
设置为true:用于安全验证,通常需要传递某些证书或令牌。
当设置为false 时,直接通过帐户和密码连接,因此通常使用useSSL=false。 【Linux系统必须添加此配置】
包com.itbaizhan;
进口
java.sql.Connection;
进口
java.sql.DriverManager;
进口
java.sql.SQLException;
/**
*获取数据库连接测试类
*/
民众
班级
Jdbc测试
{
民众
静止的
无效主(
细绳
[]争论)
扔
未找到类异常
,
SQL异常
{
//连接Mysql数据库的URL
细绳
网址=
\’jdbc:
mysql://localhost:3306/itbz?useSSL=false
\’
;
//连接数据库的用户名
细绳
姓名=
\’根\’
;
//连接数据库的密码
细绳
密码=
\’根\’
;
//通过反射实现数据库驱动的加载和注册
班级
.forName(
“com.mysql.jdbc.Driver”
);
//通过DriverManager对象获取数据库连接对象
联系
连接=
司机经理
.getConnection(url,名称,密码);
System
.out.
println
(connection);
}
}
在加载com.mysql.jdbc.Driver类信息时,会执行静态块中的代码。
在静态块中 ,数据库驱动会实例化自己并通过DriverManager的
registerDriver方法,将自己注册DriverManager驱动管理器中。
Properties文件的使用
properties文件介绍
后缀properties的文件是一种属性文件。这种文件以key=value格式
存储内容。Java中可以使用Properties工具类来读取这个文件。项
目中会将一些配置信息放到properties文件中,所以properties文
件经常作为配置文件来使用
Properties工具类
Properties工具类,位于java.util包中,该工具类继承自
Hashtable<Object,Object>。通过Properties工具类可以读
取.properties类型的配置文件。
Properties工具类中常用方法
load(InputStream is)
通过给定的输入流对象读取properties文件并解析
getProperty(String key)
根据key获取对应的value
注意:
如果properties文件中含有中文那么需要对idea进行设置。
package
com.itbaizhan;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.SQLException;
package
com.itbaizhan;
import
java.io.IOException;
import
java.util.Properties;
import
java.io.InputStream;
/**
* 读取properties配置文件的测试类
*/
public
class
PropertiesTest
{
public
static void main(String[] args) throws IOException {
//将类实例化成对象
Properties prop = new Properties();
//获取读取properties 文件的输入流对象
InputStream
is
=PropertiesTest
.
class
.
getClassLoader
().getResourceAsStream(
\”test.properties\”
);
//通过给定的输入流对象读取properties文件并解析
prop.load(
is
);
//获取properties 文件中的内容
String values1 = prop.getProperty(
\”key1\”
);
String values2 = prop.getProperty(
\”key2\”
);
System.
out
.println(values1+
\” \”
+ values2 );
}
}
优化获取数据库的连接
将可变数据放在一个文件里,文件是可以改变的
添加.properties文件
#连接mysql数据库的URL
url
= jdbc:
mysql://localhost
:
3306
/itbz?useSSL=
false
#连接数据库的用户名
name
=root
#连接数据库的密码
pwd
= root
#数据库驱动名称
driver
=com.mysql.jdbc.Driver
优化连接数据库
package com.itbaizhan;
import
java.io.IOException;
import
java.io.InputStream;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.SQLException;
import
java.util.Properties;
/**
* 优化获取数据库连接
*/
public
class
JdbcTest2 {
public
static
void
main(
String
[] args) throws IOException, ClassNotFoundException, SQLException {
//将数据从properties文件中读取出来,所以要先实例化Properties对象
Properties prop =
new
Properties();
//获取读取properties文件的字节输入流对象
InputStream is = JdbcTest2.class.getClassLoader().getResourceAsStream(
\”jdbc.properties\”
);
//读取properties文件并解析
prop.load(is);
//获取连接数据库的url
String
url = prop.getProperty(
\”url\”
);
//获取连接数据库的用户名
String
name = prop.getProperty(
\”name\”
);
//获取连接数据库的密码
String
pwd = prop.getProperty(
\”pwd\”
);
//获取连接数据库驱动全名
String
drivername = prop.getProperty(
\”driver\”
);
//加载并注册驱动
Class.forName(drivername);
//通过驱动管理器对象获取连接对象
Connection connection = DriverManager.getConnection(url,name,pwd);
System.out.println(connection);
}
}
封装JDBC工具类
package com.itbaizhan;
import
jdk.internal.dynalink.beans.StaticClass;
import
java.io.IOException;
import
java.io.InputStream;
import
java.sql.*;
import
java.util.Properties;
/**
* Jdbc工具类
*/
public
class
JdbcUtils
{
private
static
String url;
private
static
String name;
private
static
String pwd;
//io流操作不能经常进行,否则影响服务器性能
static
{
try
{
//实例化Properties对象
Properties prop =
new
Properties();
//获取读取properties文件的字节输入流对象
InputStream is =JdbcTest2.class.getClassLoader().getResourceAsStream(
\”jdbc.properties\”
);
//读取properties文件并解析
prop.load(is);
//获取连接数据库的url
url = prop.getProperty(
\”url\”
);
name = prop.getProperty(
\”name\”
);
pwd = prop.getProperty(
\”pwd\”
);
//获取数据库的密码
String drivername= prop.getProperty(
\”driver\”
);
//加载并注册驱动
Class.forName(drivername);
}
catch
(Exception e) {
e.printStackTrace();
}
}
//获取数据库连接对象(所有工具类的方法都是静态方法),通过类.方法名可以直接调用
public
static
Connection
getConnect
()
{
Connection connection = null;
//通过数据库驱动管理器获取数据库连接
try
{
connection=DriverManager.getConnection(
url
,name
,
pwd
);
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
return
connection;
}
//关闭连接对象
public
static
void
closeConnection
(Connection connection)
{
try
{
connection.close();
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
}
//提交事务
public
static
void
commit
(Connection connection)
{
try
{
connection.commit();
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
}
//事务回滚
public
static
void
rollback
(Connection connection)
{
try
{
connection.rollback();
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
}
//关闭Statement对象
public
static
void
closeStatement
(Statement statement)
{
try
{
statement.close();
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
}
//关闭ResultSet
public
static
void
closeResultSet
(ResultSet resultSet)
{
try
{
resultSet.close();
}
catch
(SQLException throwables) {
throwables.printStackTrace();
}
}
//DMl操作时关闭资源
public
static
void
closeResource
(Statement statement,Connection connection)
{
//先关闭Statement对象
closeStatement(statement);
//再关闭Connection对象
closeConnection(connection);
}
//查询时关闭资源
public
static
void
closeResource
(Statement statement,Connection connection,ResultSet resultSet)
{
//先关闭ResultSet
closeResultSet(resultSet);
//再关闭Statement对象
closeStatement(statement);
//最后关闭Connection对象
closeConnection(connection);
}
}
Statement的使用
Statement接口特点
用于执行静态 SQL 语句并返回它所生成结果的对象。 由
createStatement 创建,用于发送简单的 SQL 语句(不支持动态绑
定)。
注意:
由于Statement对象是一个执行静态SQL语句的对象,所以该对
象存在SQL注入风险
因为sql和值放在一起构成一个字符串然后交给Statement 来执行
可以用Connection对象获取JDBC中三种Statement对象
Statement:用于执行静态 SQL 语句。
PreparedStatement:用于执行预编译SQL语句。
CallableStatement:用于执行数据库存储过程。
通过Statement 添加数据
创建表
数据库创建
数据库JDBC编写代码的结构是固化的
1.try catch 语句不能再向上抛,会引起两个代码 解耦合导致数据库异常
2.获取连接
因为还要关闭它,所以要放在try— catch外面定义Connection
3.获取能够执行sql语句的Statement对象
因为还要关闭它,所以要放在try— catch外面定义Statement
4.在拿到这个statement对象后,就要通过这个对象的API来完成sql语句的执行
statement.execute()
返回一个布尔类型的值,他能够返回一个result set,
就返回一个true,
如果不能返回结果集,而是完成了一个数据更新,
就返回false
eg: statement.execute
update()
专门完成一个DML操作的,
返回一个int,表示在添加,修改,更新后在数据库当中所受影响的数据的条数
如果是查询的话,就调用
statement.
executeQuery
()
因为是完成添加用户,可以用statement.execute() ,也可以用
statement.execute
update()
5.这个()里需要一个String类型的sql语句(需要执行的)
因为没有指定列,所以按照创建的表的列的顺序添加,第一个参数是主键自增长,有没有写列,所以要用default来占位
\’ \’ 在SQl语句中表示字符串类型,但我的username是变量,我需要将值从变量中提取出来,“+username+” 拼接到语句里
最后形成了‘ “+username+ ” ’ 作为第二个参数
String sql =\”insert into users values(default ,‘\”+username+\”’,\”+userage+\”)\”;
因为是静态输入的SQl语句,所以所有的参数都需要手动拼接
6.一定要将创建的对象关掉,否则一直累积在内存中,会造成内存溢出
用创建的工具类
package
com.itbaizhan;
import
org.omg.IOP.ExceptionDetailMessage;
import
java.sql.Connection;
import
java.sql.Statement;
/**
* Statement 对象的使用
*/
public
class
StatementTest
{
/**
* 添加用户
*/
public
void
insertUsers
(String username ,
int
userage)
{
//获取连接
Connection connection =
null
;
Statement statement=
null
;
try
{
//获取connection对象
connection =JdbcUtils.getConnect();
//获取能够执行sql语句的Statement对象
statement= connection.createStatement();
//返回一个布尔类型的值,他能够返回一个result set
//就返回个true,
// 如果不能返回结果集,而是完成了一个数据更新
//就返回false
//定义需要执行的sql雨具
String sql =
\”insert into users values(default ,\’\”
+username+
\”\’,\”
+userage+
\”)\”
;
//执行sql,返回一个boolean值
boolean
execute=statement.execute(sql);
System.out.println(execute);
//这样就完成了一个insert操作
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(statement,connection);
}
}
}
7.再创建一个测试类test来测试一下这个方式能否完成用户的添加
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
StatementTest st=
new
StatementTest();
st.insertUsers(
\”old\”
,
28
);
}
}
问题一:创建表要在itbz库里创建
copy完库要刷新才行
注意引号的中英区别
Statement修改用户信息
写更新语句或删除语句的时候一定不要忘记where条件,否则会影响整个表中数据
问题注意空格
/**
* 修改用户信息
*/
public
void
updateUsers
(
int
userid ,String username,
int
userage
)
{
Connection connection=
null
;
Statement statement=
null
;
try
{
//获取连接对象
connection=JdbcUtils.getConnect();
//获取Statement对象
statement=connection.createStatement();
//定义sql语句
String sql=
\”update users set username=\’\”
+username+
\”\’, userage=\”
+userage+
\” where userid=\”
+userid;
//执行sql语句
int
i= statement.executeUpdate(sql);
System.
out
.println(i);
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(statement,connection);
}
}
测试
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
StatementTest st=
new
StatementTest();
// st.insertUsers(\”old\”,28);
st.updateUsers(
1
,
\”tangan\”
,
19
);
}
}
返回的值不需要的话可以不要将他打印出来
删除数据
public
void
deleteUsersById
(
int
userid
)
{
Connection connection=
null
;
Statement statement=
null
;
try
{
//.获取数据库连接
connection=JdbcUtils.getConnect();
// 获取Statement对象
statement=connection.createStatement();
//定义执行删除的语句
String sql =
\”delete from users where userid=\”
+userid;
//执行sql
int
i= statement.executeUpdate(sql);
System.
out
.println(i);
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(statement,connection);
}
}
test
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
StatementTest st=
new
StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
st.deleteUsersById(
2
);
}
}
PreparedStatement对象简介(重点)
继承自 Statement 接口,由 preparedStatement方法创建。
PreparedStatement具有预编译SQL语句能力,所以
PreparedStatement 对象比 Statement 对象的效率更高,由于实
现了动态的参数绑定,所以可以防止 SQL 注入,所以我们一般都使
用 PreparedStatement。
PreparedStatement对象的特点:
PreparedStatement 接口继承 Statement 接口
PreparedStatement 效率高于 Statement
PreparedStatement 支持动态绑定参数
PreparedStatement 具备 SQL 语句预编译能力
使用 PreparedStatement 可防止出现 SQL 注入问题
PreparedStatement 的预编译能力
语句的执行步骤
语法和语义解析
优化 sql 语句,制定执行计划
执行并返回结果
但是很多情况,我们的一条 sql 语句可能会反复执行,或者每次执
行的时候只有个别的值不同(比如 select 的 where 子句值不同,
update 的 set 子句值不同,insert 的 values 值不同)。 如果每次都
需要经过上面的词法语义解析、语句优化、制定执行计划等,则效
率就明显不行 了。
所谓预编译语句就是将这类语句中的值用占位符
替代,可以视为将 sql 语句模板化或者说参数化预编译语句的优势
在于:一次编译、多次运行,省去了解析优化等过程;此外预编译
语 句能防止 sql 注入
通过PrepareStatement 对象介绍
preparedStatement 先是对sql语法进行判断如果语句的结构没有问题就交给语义解析器
优化器结合语句特点生成一个执行计划
重要的是他会缓存这个执行计划,下次再输入相同的Sql语句就不需要进行语法和语义的解析以及优化,直接调用与之对应的执行计划去执行就好了
如果用statemet的话,它是将结构和值作为整体一条数据,是不会缓存的
而PrepareStatement就将SQL语句和值分离,可以缓存SQL语句
只有在相同的Connection ,相同的sql 语句下,值不同才会有效
Preparement 添加数据
Sql语句里用?占位(即便是字符串类型)?是PreparedStatement对象中的绑定参数的占位符。问号的位置是从1开始计数
PreparedStatement 是Statement的子接口
因为已经在try-catch 语句外边定义了类型,所以对象前面不用再加类型
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* PreparedStatement使用的测试类
*/
public
class
PreparedStatementTest
{
/**
*添加用户
*/
public
void
insertUsers
(
String username ,
int
userage
)
{
Connection connection =
null
;
PreparedStatement ps =
null
;
try
{
//获取数据库连接
connection=JdbcUtils.getConnect();
//执行Sql语句
String sql =
\”insert into users values(default,?,?)\”
;
//创建PreparedStatement对象
ps= connection.prepareStatement(sql);
//完成参数的绑定
ps.setString(
1
,username);
ps.setInt(
2
,userage);
int
i= ps.executeUpdate();
System.
out
.println(i);
}
catch
(Exception e ){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
}
test测试
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
PreparedStatementTest pt=
new
PreparedStatementTest();
pt.insertUsers(
\”oldlu\”
,
38
);
}
}
更新数据
/**
* 根据用户ID修改用户姓名与年龄
*/
public
void
updateUserById
(
int
userid,String username,
int
userage
)
{
Connection connection=
null
;
PreparedStatement ps =
null
;
try
{
//获取数据库连接对象
connection = JdbcUtils.getConnect();
String sql =
\”update users set username = ? , userage=? where userid=? \”
;
//创建PreparedStatement对象
ps=connection.prepareStatement(sql);
//参数绑定
ps.setString(
1
,username);
ps.setInt(
2
,userage);
ps.setInt(
3
,userid);
int
i =ps.executeUpdate();
System.
out
.println(i);
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
test
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
PreparedStatementTest pt=
new
PreparedStatementTest();
//pt.insertUsers(\”oldlu\”,38);
pt.updateUserById(
3
,
\”kevin\”
,
21
);
}
}
删除数据
/**
* 根据用户ID删除指定用户
*/
public
void
deleteUsersById
(
int
userid
)
{
Connection connection=
null
;
PreparedStatement ps=
null
;
try
{
//获取数据库连接对象
connection=JdbcUtils.getConnect();
String sql=
\”delete from users where userid=?\”
;
ps=connection.prepareStatement(sql);
//绑定参数
ps.setInt(
1
,userid);
int
i=ps.executeUpdate();
System.
out
.println(i);
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
test
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
PreparedStatementTest pt=
new
PreparedStatementTest();
//pt.insertUsers(\”oldlu\”,38);
//pt.updateUserById(3,\”kevin\”,21);
pt.deleteUsersById(
3
);
}
}
ResultSet
ResultSet接口的特点
ResultSet用来存放数据库查询操作获得结果集,通过对ResultSet
的操作可以获取查询到的结果集数据。
ResultSet 对象中存放的并不是我们查询到的所有的结果集。它
采用分块加载的方式来载入结果集数据。
ResultSet特点
1.ResultSet 对象具有指向其当前数据行的指针。最初,指针被置于第一行之前。next 方法将指针移
动到下一行;因为该方法在 ResultSet 对象中没有下一行时返回 false,所以可以在 while 循环中使
用它来迭代结果集。
2.默认的 ResultSet 对象仅有一个向前移动的指针。因此,只能迭代它一次,并且只能按从第一行到
最后一行的顺序进行。
3.ResultSet 接口提供用于获取当前行检索列值的获取方法(getBoolean、getLong 等)。可以使用
列的索引位置或列的名称检索值。
package
com.itbaizhan;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.*;
/**
* 获取结果集测试类
*/
public
class
ResultSetTest
{
/**
* 查询所有用户
*/
public
void
selectUsersAll
()
{
Connection connection =
null
;
PreparedStatement ps =
null
;
ResultSet resultSet=
null
;
try
{
//获取数据库连接
connection=JdbcUtils.getConnect();
String sql=
\”select * from users \”
;
ps=connection.prepareStatement(sql);
//执行查询
resultSet=ps.executeQuery();
//操作ResultSet对象获取查询的结果集
while
(resultSet.next()){
//获取列的数据
int
userid=resultSet.getInt(
\”userid\”
);
//返回了第一个单元格的数据
String username=resultSet.getString(
\”username\”
);
int
userage=resultSet.getInt(
\”userage\”
);
System.out.println(userid+
\” \”
+ username+
\” \”
+userage);
}
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(resultSet,ps,connection);
}
}
}
test
package
com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.ResultSet;
import
java.sql.Statement;
public
class
Test
{
public
static
void
main
(String[] args)
{
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
// PreparedStatementTest pt=new PreparedStatementTest();
//pt.insertUsers(\”oldlu\”,38);
//pt.updateUserById(3,\”kevin\”,21);
// pt.deleteUsersById(3);
ResultSetTest rt =
new
ResultSetTest();
rt.selectUsersAll();
}
}
ORM编程思想
ORM简介
对象关系映射(英语:Object Relational Mapping,简称ORM,或
O/R mapping)是一种为了解决面向对象语言与关系数据库存在的
互不匹配的现象
实体类(存储类)
实体类就是一个定义了属性,拥有getter、setter、无参构造方法
(基本必备)的一个类。实体类可以在数据传输过程中对数据进行
封装,相当于一个“工具”、“容器”、“载体”,能存储、传输数据,能
管理数据
处理数据的叫(过程类)之前写的都叫过程类
实体类特点:
1 实体类名,尽量和数据库中的表名一一对应
2 实体类中的属性对应数据库表中的字段,相关的命名最好也一一对应
3 实体类内方法主要有,getter、setter方法,用于设置、获取数据
4 实体类属性一般为private类型,方法为public类型
5 实体类应该有,无参、有参构造方法(随手添加一个无参构造方法,在创建对象的时候更加灵活,而且以后会学到ORM的一些高级框架会要求必须有无参构造方法)
ORM使用
现在还是手动映射
将查询到的数据有效的管理起来
Users实体类
因为每查询到一条数据,存到一个User类里
所以应该在while 循环里实例化
但如果是主键或者唯一性约束的就可以放在while循环外面定义
如果是返回多条,一定是在while循环里定义的
每次实例化的对象要保存,否则就会被覆盖,于是就放在一个集合里,集合要在循环的外边创建
再讲结果集改造
按照之前的代码添加的话,那么没有返回值,改方法后就谁调用这个方法谁就会获得所有用户的信息
原理:将对象映射到Users类里,再将对象放进集合里,再返回集合,最后遍历该容器
package com.itbaizhan;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.*;
import
java.util.ArrayList;
import
java.util.List;
/**
* 获取结果集测试类
*/
public
class
ResultSetTest
{
/**
* 查询所有用户
*/
public
List<Users>
selectUsersAll
()
{
Connection connection =null;
PreparedStatement ps =null;
ResultSet resultSet=null;
List<Users>
list
=
new
ArrayList<>();
try
{
//获取数据库连接
connection=JdbcUtils.getConnect();
String sql=
\”select * from users \”
;
ps=connection.prepareStatement(sql);
//执行查询
resultSet=ps.executeQuery();
//操作ResultSet对象获取查询的结果集
while
(resultSet.next()){
//获取列的数据
int
userid=resultSet.getInt(
\”userid\”
);
//返回了第一个单元格的数据
String username=resultSet.getString(
\”username\”
);
int
userage=resultSet.getInt(
\”userage\”
);
// System.out.println(userid+\” \”+ username+\” \”+userage);
//ORM映射处理
Users users =
new
Users();
//将取到的数据放到users对象的那3个属性里
users.setUserid(userid);
users.setUsername(username);
users.setUserage(userage);
list
.add(users);
}
}
catch
(Exception e){
e.printStackTrace();
}finally {
JdbcUtils.closeResource(resultSet,ps,connection);
}
return
list
;
}
}
test
package com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.ResultSet;
import
java.sql.Statement;
import
java.util.List;
public
class
Test
{
public
static
void
main
(String[] args)
{
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
// PreparedStatementTest pt=new PreparedStatementTest();
//pt.insertUsers(\”oldlu\”,38);
//pt.updateUserById(3,\”kevin\”,21);
// pt.deleteUsersById(3);
ResultSetTest rt =
new
ResultSetTest();
//rt.selectUsersAll();
//遍历
List<Users>
list
=rt.selectUsersAll();
for
(Users users:
list
){
System.out.println(users.getUserid()+
\” \”
+ users.getUsername()+
\” \”
+ users.getUserage());
}
}
}
Sql注入
package com.itbaizhan;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* sql注入测试类
*/
public
class
SqlInjectTest
{
/**
* 体现sql注入
*/
public
void
sqlInject
(
String username ,
int
userage
)
{
Connection connection=
null
;
Statement statement=
null
;
ResultSet resultSet=
null
;
try
{
//获取连接
connection=JdbcUtils.getConnect();
//创建Statement对象
statement=connection.createStatement();
//定义sql语句
String sql=
\”select * from users where username=\’\”
+username+
\”\’and userage=\”
+userage;
System.
out
.println(sql);
//执行sql语句
resultSet=statement.executeQuery(sql);
//处理结果集
while
(resultSet.next()){
int
userid=resultSet.getInt(
\”userid\”
);
String name =resultSet.getString(
\”username\”
);
int
age= resultSet.getInt(
\”userage\”
);
System.
out
.println(userid+
\” \”
+name+
\” \”
+age);
}
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(resultSet,statement,connection);
}
}
public
static
void
main
(
String[] args
)
{
SqlInjectTest sit=
new
SqlInjectTest();
sit.sqlInject(
\”tangan\”
,
19
);
}
}
SQL注入
public
static
void
main
(String[] args)
{
SqlInjectTest sit=new SqlInjectTest
();
sit.sqlInject(
“tangan\’or 1=1 — ”
,
19
);
}
结果:
select * from users where username=
\’tangan\’or 1=1
–
–
\’and userage=19 #‘单引号与前半部分构成一个整体,1=1是必然成立的条件
“ — ” 后面是注释部分,相当于Sql语句为:select * from users where username=\’tangan\’or 1=1 查username 为tangan 以及所有的数据
1 tangan 19
2 oldlu 38
sql注入
解决sql 注入
用PreparedStatement
public
void
noSqlInject
(
String username,
int
userage
)
{
Connection connection =
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
try
{
//获取连接
connection=JdbcUtils.getConnect();
//创建preparedStatement对象
ps=connection.prepareStatement(
\”select * from users where username=? and userage =?\”
);
//绑定参数
ps.setString(
1
,username);
ps.setInt(
2
,userage);
//执行SQL
rs=ps.executeQuery();
//参数绑定
while
(rs.next()){
int
userid =rs.getInt(
\”userid\”
);
String name =rs.getString(
\”username\”
);
int
age=rs.getInt(
\”userage\”
);
System.
out
.println(userid+
\” \”
+name+
\” \”
+age );
}
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(rs,ps,connection);
}
}
test
public
static
void
main
(
String[] args
)
{
SqlInjectTest sit=
new
SqlInjectTest();
sit.sqlInject(
\”tangan\’or 1=1 — \”
,
19
);
System.
out
.println(
\”******************************************\”
);
sit.noSqlInject(
\”tangan\’or 1=1 — \”
,
19
);
}
没有输出结果
sql注入解决
批量添加数据简介
在JDBC中通过PreparedStatement的对象的addBatch()和
executeBatch()方法进行数据的批量插入。
addBatch()把若干SQL语句装载到一起,然后一次性传送到数据库执行,即是批量处理sql数据的。
executeBatch()会将装载到一起的SQL语句执行。
注意:
MySql默认情况下是不开启批处理的。
数据库驱动从5.1.13开始添加了一个对rewriteBatchStatement
的参数的处理,该参数能够让MySql开启批处理。在url中添加
该参数:rewriteBatchedStatements=true
参数
#连接mysql数据库的URL
url
= jdbc:
mysql://localhost
:
3306
/itbz?useSSL=
false
&userUnicode=
true
&characterEncoding=utf-
8
#连接数据库的用户名
name
=root
#连接数据库的密码
pwd
= root
#数据库驱动名称
driver
=com.mysql.jdbc.Driver
数据的批量添加
ps.executeBatch(); 返回值会出现正数,表示更新的条数,出现负数,表示不知道更新的数据条数,但都表示批量操作成功
修改配置
#连接mysql数据库的URL
url
= jdbc:mysql://localhost:
3306
/itbz?useSSL=
false
&rewriteBatchedStatements=
true
#连接数据库的用户名
名称
=根
#连接数据库的密码
pwd
= 根
#数据库驱动名称
驱动程序
=com.mysql.jdbc.Driver
缓存,否则交互次数过多,效率低
package
com.itbaizhan;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
/**
* 向mysql 数据库批量添加数据测试类
*/
public
class
AddBatchTest
{
/**
* 批量添加数据方法1:
*/
public
void
addBatch1
()
{
Connection connection=
null
;
PreparedStatement ps=
null
;
try
{
//创建连接
connection=JdbcUtils.getConnect();
//创建PreparedStatement
ps=connection.prepareStatement(
\”insert into users values(default,?,?)\”
);
//绑定参数
for
(
int
i=
0
;i<
1000
;i++){
//绑定username
ps.setString(
1
,
\”ITBZ\”
+i);
//绑定userage
ps.setInt(
2
,
20
);
//缓存sql
ps.addBatch();
}
//执行sql
ps.executeBatch();
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
public
static
void
main
(String[] args)
{
AddBatchTest addBatchTest=
new
AddBatchTest();
addBatchTest.addBatch1();
}
}
缓存量过大也是不适合一次性缓存到本地的内存中,会造成内存泄漏
记得清除缓存,适用于数据量非常大的
/**
* 批量添加数据方法2
*/
public
void
addBatch2
()
{
Connection connection=
null
;
PreparedStatement ps=
null
;
try
{
//创建连接
connection=JdbcUtils.getConnect();
//创建PreparedStatement
ps=connection.prepareStatement(
\”insert into users values(default,?,?)\”
);
//绑定参数
for
(
int
i=
0
;i<
2000
;i++){
//绑定username
ps.setString(
1
,
\”ITBZ\”
+i);
//绑定userage
ps.setInt(
2
,
20
);
//缓存sql
ps.addBatch();
//每500插入一次
if
(i%
500
==
0
){
//执行sql
ps.executeBatch();
//清除缓存
ps.clearBatch();
}
}
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
i%
500 ==
0 取模为0 说明是偶数,每500个偶数存一次
i<1000,所以不会存起来
JDBC事务
事务简介
1
事务:
事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地
执行,要么完全地不执行。
2
事务操作流程:
开启事务
提交事务
回滚事务
JDBC中事务处理特点
在JDBC中,使用Connection对象来管理事务,默认为自动提交事
务。可以通过setAutoCommit(boolean autoCommit)方法设置事
务是否自动提交,参数为boolean类型,默认值为true,表示自动
提交事务,如果值为false则表示不自动提交事务,需要通过
commit方法手动提交事务或者通过rollback方法回滚事务
JDBC事务的实现
先设置为手动最后提交
/**
* 批量添加数据方法2
*/
public
void
addBatch2
()
{
Connection connection=
null
;
PreparedStatement ps=
null
;
try
{
//创建连接
connection=JdbcUtils.getConnect();
//设置事物的提交方式,将自动提交改为手动提交
connection.setAutoCommit(
false
);
//创建PreparedStatement
ps=connection.prepareStatement(
\”insert into users values(default,?,?)\”
);
//绑定参数
for
(
int
i=
0
;i<
1500
;i++){
//绑定username
ps.setString(
1
,
\”ITBZ\”
+i);
//绑定userage
ps.setInt(
2
,
20
);
//缓存sql
ps.addBatch();
//每500插入一次
if
(i%
500
==
0
){
//执行sql
ps.executeBatch();
//清除缓存
ps.clearBatch();
}
}
//提交书屋
connection.commit();
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
出现异常还要回滚
public
void
addBatch2
()
{
Connection connection=
null
;
PreparedStatement ps=
null
;
try
{
//创建连接
connection=JdbcUtils.getConnect();
//设置事物的提交方式,将自动提交改为手动提交
connection.setAutoCommit(
false
);
//创建PreparedStatement
ps=connection.prepareStatement(
\”insert into users values(default,?,?)\”
);
//绑定参数
for
(
int
i=
0
;i<
1500
;i++){
//绑定username
ps.setString(
1
,
\”ITBZ\”
+i);
//绑定userage
ps.setInt(
2
,
20
);
//缓存sql
ps.addBatch();
//每500插入一次
if
(i%
500
==
0
){
//执行sql
ps.executeBatch();
//清除缓存
ps.clearBatch();
}
}
//提交书屋
connection.commit();
}
catch
(Exception e){
e.printStackTrace();
//回滚事务
JdbcUtils.rollback(connection);
}
finally
{
JdbcUtils.closeResource(ps,connection);
}
}
卡片4
模糊查询
like 里的通配直接用问号,最后参数绑定的时候才用% 表示左通配还是右通配,还是两端通配,因为%不是sql语句的一部分,而是条件的一部分
setString 方法可以将字符串类型的参数直接加上两个单引号绑定拼接
ps.setString(1,\”%\”+username+\”%\”);【也不太好】因为这就将内容写死了,最好应该是ps.setString(1,username);在给定具体值的时候
再决定在哪通配
like查询一定会返回多条数据,所以要用while
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.
List
;
/**
* 模糊查询测试类
*/
public
class
FuzzyQueryTest
{
/**
* 根据用户名称模糊查询用户信息
*/
public
List
<Users> fuzzyQuery(String username){
//创建一个list对象
List
<Users>
list
=
new
ArrayList<>();
Connection connection=
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
try
{
//获取数据库连接
connection=JdbcUtils.getConnect();
//创建PreparedStatement对象
ps=connection.prepareStatement(
\”select * from users where username like ? \”
);
//参数绑定
ps.setString(
1
,username);
//执行sql语句
rs=ps.executeQuery();
while
(rs.next()){
//将每条查询出来的数据放在user里作为一个单独的对象
Users user=
new
Users();
user.setUserid(rs.getInt(
\”userid\”
));
user.setUsername(rs.getString(
\”username\”
));
user.setUserage(rs.getInt(
\”userage\”
));
//再将创建出来的对象放进list容器里
list
.add(user);
}
}
catch
(
Exception
e){
e.printStackTrace();
}
finally
{
JdbcUtils.closeResource(rs,ps,connection);
}
//返回列表
return
list
;
}
public
static
void main(String[] args) {
//将这个类实例化
FuzzyQueryTest ft =
new
FuzzyQueryTest();
List
<Users> users=ft.fuzzyQuery(
\”%d%\”
);
//遍历这个list容器
for
(Users user1:users){
System.out.println(user1.getUserid()+
\” \”
+user1.getUsername()+
\” \”
+ user1.getUserage()); }
}
}
动态条件查询
根据用户给定的条件来决定执行什么样的查询
之所以用list类型来定义这个方法,是因为动态查询的结果不止一个
之所以要用Users users作为参数,是应为未来要把查询的这个条件放到这个users对象的属性当中来传递
因为有可能是有条件,有可能是没条件,至于多条件,则依赖于个users对象的属性来存放
SQL语句也是不确定的,因为查询的条件要根据users 对象的属性有哪些来判断,所以要拼语句
将拼接语句凡在另一个方法里面,好处是如果这个类里面有其他的方法要用到sql语句的拼接就方便多了,且结构清晰
因为只为这个类服务,所以可将这个方法设置为private
用StringBuilder 来做字符串的拼接
前面的投影部分相同只是where 条件不同
注意只有在ps.setString(1,username);参数绑定 里字符串类型不用加单引号,其他方法里都要加
分别对参数判断符合后拼接进SQL语句里,因为如果第一个userid 不满足条件,那么将会直接将and拼接到where后面,明显
不行,那么解决方法就是用1=1 的方法解决拼接格式问题 1=1 就是select * 的意思
注意append双引号中and前面一定要加空格,不然容易与上个语句连在一起
最后用toString方法
查所有数据就是queryUsers里直接放users对象,不给users对象添加属性
public
static
void
main
(String[] args)
{
DynamicConditionQueryTest dt=
new
DynamicConditionQueryTest();
Users users=
new
Users();
List<Users>
list
=dt.queryUsers(users);
for
(Users user2:
list
){
System.out.println(user2.getUserid()+
\” \”
+user2.getUsername()+
\” \”
+ user2.getUserage());
}
}
}
而添加属性
package com.itbaizhan;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.util.ArrayList;
import
java.util.List;
/**
* 动态查询测试类
*/
public
class
DynamicConditionQueryTest
{
/**
* 动态查询Users
*/
public
List<Users>
queryUsers
(Users users)
{
//创建一个list对象
List<Users>
list
=
new
ArrayList<>();
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
//获取数据库连接
connection = JdbcUtils.getConnect();
//拼接查询sql语句
String sql =
this
.generateSql(users);
//创建PreparedStatement对象
ps = connection.prepareStatement(sql);
//执行sql语句
rs = ps.executeQuery();
while
(rs.next()) {
//将每条查询出来的数据放在user里作为一个单独的对象
Users user =
new
Users();
user.setUserid(rs.getInt(
\”userid\”
));
user.setUsername(rs.getString(
\”username\”
));
user.setUserage(rs.getInt(
\”userage\”
));
//再将创建出来的对象放进list容器里
list
.add(user);
}
}
catch
(Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.closeResource(rs, ps, connection);
}
//返回列表
return
list
;
}
/**
* 生成动态查询sql
*/
private
String
generateSql
(Users users)
{
StringBuffer sb =
new
StringBuffer(
\”select * from users where 1=1 \”
);
if
(users.getUserid() >
0
) {
sb.append(
\” and userid = \”
).append(users.getUserid());
}
if
(users.getUsername() != null && users.getUsername().length() >
0
) {
sb.append(
\” and username = \’\”
).append(users.getUsername()).append(
\”\’\”
);
}
if
(users.getUserage()>
0
){
sb.append(
\” and userage = \”
).append(users.getUserage());
}
return
sb.toString() ;
}
public
static
void
main
(String[] args)
{
DynamicConditionQueryTest dt=
new
DynamicConditionQueryTest();
Users users=
new
Users();
users.setUsername(
\”oldli\”
);
List<Users>
list
=dt.queryUsers(users);
for
(Users user2:
list
){
System.out.println(user2.getUserid()+
\” \”
+user2.getUsername()+
\” \”
+ user2.getUserage());
}
}
}
当mysql语句出错的时候,可以将语句打印出来,判断错在哪
分页查询
要多少数据,差多少数据,大大减少数据库服务器的内存消耗
分页查询分类:
1
物理分页:要多少查多少(主要)
在数据库执行查询时(实现分页查询),查询需要的数据—依赖数据库的SQL语句
在SQL查询时,从数据库只检索分页需要的数据
通常不同的数据库有着不同的物理分页语句
MySql物理分页采用limit关键字
2
逻辑分页:(仍存在内存溢出的复方鲜)
在sql查询时,先从数据库检索出所有数据的结果集,在程序内,通过逻辑语句获得分页需要的数
据
如何在MySql中实现物理分页查询
使用limit方式。
limit的使用
select
*
from
tableName
limit
m,n
其中m与n为数字。n代表需要获取多少行的数据项,而m代表从哪
开始(以0为起始)。
分页查询
必须要是double类型数才能进行该方法,得到的数强转为int类型
检查时就检查结果集有没有放进page里,总条数有没有放到page里,总页数有没有放到page里
page
package com.itbaizhan;
import
java.util.List;
/**
* 分页查询实体类
*/
public
class
Page
<T> {
//当前页
private
int
currentPage;
//每页显示的条数
private
int
pageSize;
//总页数
private
int
totalCount;
//总页数
private
int
totalPage;
//结果集
private
List<T> result;
public
int
getCurrentPage
()
{
return
currentPage;
}
public
void
setCurrentPage
(
int
currentPage)
{
this
.currentPage = currentPage;
}
public
int
getPageSize
()
{
return
pageSize;
}
public
void
setPageSize
(
int
pageSize)
{
this
.pageSize = pageSize;
}
public
int
getTotalCount
()
{
return
totalCount;
}
public
void
setTotalCount
(
int
totalCount)
{
this
.totalCount = totalCount;
}
public
int
getTotalPage
()
{
return
totalPage;
}
public
void
setTotalPage
(
int
totalPage)
{
this
.totalPage = totalPage;
}
public
List<T>
getResult
()
{
return
result;
}
public
void
setResult
(List<T> result)
{
this
.result = result;
}
}
pageTest
package com.itbaizhan;
import
javax.imageio.stream.ImageInputStream;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.util.ArrayList;
import
java.util.List;
/**
* 分页查询测试类
*/
public
class
PageTest
{
/**
* 分页查询Users
*/
public
Page<Users>
selectPage
(Page page)
{
Connection connection=null;
PreparedStatement ps=null;
ResultSet rs=null;
List<Users>
list
=
new
ArrayList<>();
try
{
connection=JdbcUtils.getConnect();
ps=connection.prepareStatement(
\”select * from users limit ?,?\”
);
//绑定m值
ps.setInt(
1
,(page.getCurrentPage()
-1
)*page.getPageSize());
//绑定n值
ps.setInt(
2
,page.getPageSize());
//执行查询
rs=ps.executeQuery();
//处理结果集
while
(rs.next()){
//完成ORM映射
Users users=
new
Users();
users.setUserid(rs.getInt(
\”userid\”
));
users.setUsername(rs.getString(
\”username\”
));
users.setUserage(rs.getInt(
\”userage\”
));
list
.add(users);
}
//将结果集存放到Page对象中
page.setResult(
list
);
//查询总条数
ps=connection.prepareStatement(
\”select count(*) from users\”
);
//执行查询
rs=ps.executeQuery();
while
(rs.next()){
int
count = rs.getInt(
1
);
//保存总条数
page.setTotalCount(count);
//换算总页数=总条数/每页显示的条数 向上取整
int
totalPage=(
int
)Math.
ceil
(
1.0
*count/page.getPageSize());
//保存总页数
page.setTotalPage(totalPage);
}
}
catch
(Exception e){
e.printStackTrace();
}finally{
JdbcUtils.closeResource(rs,ps,connection);
}
return
page;
}
public
static
void
main
(String[] args)
{
PageTest pt=
new
PageTest();
Page page=
new
Page();
page.setCurrentPage(
1
);
page.setPageSize(
2
);
Page page1=pt.selectPage(page);
System.out.println(
\”总条数:\”
+page1.getTotalCount());
System.out.println(
\”总页数:\”
+page1.getTotalPage());
System.out.println(
\”当前页:\”
+page1.getCurrentPage());
System.out.println(
\”每页显示的条数:\”
+page1.getPageSize());
List<Users>
list
=page1.getResult();
for
(Users user:
list
){
System.out.println(user.getUserid()+
\” \”
+ user.getUsername()+
\” \”
+user.getUserage() );
}
}
}
连接数据库
1.直连 现用现创建Connection对象,用完关闭
缺点:效率低(TCP三次握手,)
2..池连: 什么是数据库连接池
数据库连接池(Connection pooling)是程序启动时建立足够的数
据库连接,并将这些连接组成一个连接池,由程序动态地对池中的
连接进行申请,使用,释放(用的时候从池里拿,用完还回去)
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建
立一个
不使用数据库连接池存在的问题
1.普通的JDBC数据库连接使用 DriverManager 来获取,每次向数
据库建立连接的时候都要将 Connection加载到内存中,再验证
用户名和密码,所以整个过程比较耗时。
2.需要数据库连接的时候,就向数据库要求一个,执行完成后再断
开连接。这样的方式将会消耗大量的资源和时间。数据库的连接
资源并没有得到很好的重复利用。若同时有几百人甚至几千人在
线,频繁的进行数据库连接操作将占用很多的系统资源,严重的
甚至会造成服务器的崩溃。
3.对于每一次数据库连接,使用完后都得断开。否则,如果程序出
现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将
导致重启数据库
JDBC数据库连接池的必要性
1·.数据库连接池的基本思想:为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连
接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
2.数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连
接,而不是重新建立一个。
3.数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由
最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么
多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序
向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
数据库连接池的优点
1 资源重用:由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系
统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
2 更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池
中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接避免了
数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
3 新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置
实现某一应用最大可用数据库连接数的限制避免某一应用独占所有的数据库资源.
4 统一的连接管理:避免数据库连接泄露在较为完善的数据库连接池实现中,可根据预先的占用超时
设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
常用的数据库连接池
c3p0:是一个开源组织提供的数据库连接池,速度相对较慢,稳定性还可以。
DBCP:是Apache提供的数据库连接池。速度相对c3p0较快,但自身存在bug。
Druid:是阿里提供的数据库连接池,据说是集DBCP、c3p0优点于一身的数据库连接池,目前经
常使用。
Druid简介
将jar包拷贝到lib 文件夹里,还需要 add as library 才能导进项目中
Druid使用步骤
1
导入druid-1.2.8.jar包到lib目录下,并引入到项目中
2
在src下创建一个druid.properties类型的文件,并写入
3
加载配置文件
4
获取连接池对象
在javax.sql下的接口
在java.sql 下的接口
5
通过连接池对象获取连接
DruidTest.class.getClassLoader()获得类加载器.getResourceAsStream(\”\”)加载什么配置文件,返回一个IO流,接受一下
Properties的包要导对了
import java.util.Properties;
pos.load(inputStream); 有异常,需要抛出
DataSource ds= DruidDataSourceFactory
.createDataSource(pos);有异常要抛出 ,所以直接抛Exception
ds.getConnection();返回一个Connection对象
druid.properties
url
=jdbc:
mysql://localhost
:
3306
/itbz?useSSL=
false
driverClassName
=com.mysql.jdbc.Driver
username
=root
password
=root
initialSize
=
10
maxActive
=
20
druidTest
package com.itbaizhan;
import
com.alibaba.druid.pool.DruidDataSourceFactory;
import
javax.sql.DataSource;
import
java.io.InputStream;
import
java.sql.Connection;
import
java.util.Properties;
/**
* Durid连接池测试类
*/
public
class
DruidTest
{
public
static
void
main
(String[] args)
throws Exception
{
//获取读取druid配置文件的字节输入流
InputStream inputStream=DruidTest.class.getClassLoader().getResourceAsStream(
\”druid.properties\”
);
//创建Properties对象
Properties pos=
new
Properties();
//加载配置文件
pos.load(inputStream);
//获取连接池对象
DataSource ds= DruidDataSourceFactory.createDataSource(pos);
//获取连接
Connection connection=ds.getConnection();
System.out.println(connection);
}
}
druid 封装工具类
dataSource只有 一个,所以放在Static 即可
应用程序分层
应用程序分层简介
应用程序分层是指通过创建不同的包来实现项目的分层,将项目中
的代码根据功能做具体划分,并存放在不同的包下。
三层结构
三层结构就是将整个业务应用划分为:表述层、业务逻辑层 、数据
访问层。区分层次的目的即为了“高内 聚低耦合”的思想。在软件体
系架构设计中,分层式结构是最常见,也是最重要的一种结构。
层与层之间要松耦合,有利于代码的维护
在写介于Jdbc操作数据库的时候,要求用trycatch 而不是抛出异常,catch 是为了防止出现sql.Exception 异常,如果不在数据访问层catch掉这个异常,将会抛到业务逻辑层,业务逻辑层拿到了数据访问层的异常,造成层与层之间紧耦合现象。所以如果数据访问层真的出现了异常,还要通过信息告诉业务逻辑层,可以在catch里抛用户自定义异常,这样渗透到业务逻辑层里的只是用户自定义异常,不是数据访问层的异常,解决二者异常
分层优点
1
分层结构将应用系统划分为若干层,每一层只解决问题的一部
分,通过各层的协作提供整体解决方案。大的问题被分解为一系
列相对独立的子问题,局部化在每一层中,这样就有效的降低了
单个问题的规模和复杂度,实现了复杂系统的第一步也是最为关
键的一步分解。
2
分层结构具有良好的可扩展性,为应用系统的演化增长提供了一
个灵活的支持,具有良好的可扩展性。增加新的功能时,无须对
现有的代码做修改,业务逻辑可以得到最大限度的重用。
3
分层结构易于维护。在对系统进行分解后,不同的功能被封装在
不同的层中,层与层之间的耦合显著降低。因此在修改某个层的
代码时,只要不涉及层与层之间的接口,就不会对其他层造成严
重影响。
分层命名
表述层:web或controller
业务层:service
数据访问层:dao (Data Access Object)
基于Driuid封装工具类
package com.itbaizhan;
import
com.mysql.jdbc.JDBC4PreparedStatement;
import
java.sql.Connection;
import
java.sql.ResultSet;
import
java.sql.Statement;
import
java.util.Collections;
import
java.util.List;
public
class
Test
{
public
static
void main(
String
[] args) {
// StatementTest st=new StatementTest();
// st.insertUsers(\”old\”,28);
// st.updateUsers(1,\”tangan\”,19);
// st.deleteUsersById(2);
// PreparedStatementTest pt=new PreparedStatementTest();
//pt.insertUsers(\”oldlu\”,38);
//pt.updateUserById(3,\”kevin\”,21);
// pt.deleteUsersById(3);
// ResultSetTest rt =new ResultSetTest();
// //rt.selectUsersAll();
// //遍历
// List<Users>list =rt.selectUsersAll();
// for (Users users:list){
// System.out.println(users.getUserid()+ \” \”+ users.getUsername()+\” \”+ users.getUserage());
// }
Connection
conn=
JdbcDuridUtill
.getConnection();
System
.out.
println
(conn);
}
}
druid文件
url=jdbc:mysql://localhost:3306/itbz?useSSL=false
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=10
maxActive=20
}
问题:
分析:方法中的类型和你现在返回值的类型不一致
这个方法返回的不是Connection类型吗
是Connection类型,但是不止一个包有这个类
问题解决:删掉 import java.sql.Connection;
应用程序分层实现
分层实现
创建lib目录,用于加载jar 类包
在实体类里重载toString方法
异常两种类型:1.运行时异常 2.非运行时异常(编译异常)
创建相关包和类方法
在表述层调用业务层代码,在业务层调用数据操作层或者叫持久层代码
对于这个业务的实现编码过程当中,你的编码的顺序可以先写web 包,再写业务包,再写数据持久层,也可以乱着顺序写
建议从后往前写即倒着写
如果是操作的Users表,就要以表名作为前缀再加上Dao作为接口名
接口复习
问题:
Connection2解决
Statement 同理解决
import java.sql.PreparedStatement;
没有new Users是因为,如果相应的ID有Users就在循环里将其new出来,放里面就行了,如果没有while循环就不循环,
new users就不执行。那么就会返回users=null; 查询的时候就方便判断有无users对象
数据层
接口
package
com.itbaizhan.dao;
import
com.itbaizhan.pojo.Users;
public
interface
UsersDao
{
//接口里必须实现的方法,省略了public abstract
/**
* 根据用户ID查询用户
*/
Users
selectUsersById
(
int
userid)
;
}
实现类
package
com.itbaizhan.dao.impl;
import
com.itbaizhan.JdbcDuridUtill;
import
com.itbaizhan.dao.UsersDao;
import
com.itbaizhan.exception.ApplicationException;
import
com.itbaizhan.pojo.Users;
import
java.sql.PreparedStatement;
import
java.sql.Connection;
import
java.sql.ResultSet;
/**
* 接口实现类
*/
public
class
UsersDaoImpl
implements
UsersDao
{
/**
* 根据用户ID查询用户
*
@param
userid
*
@return
*/
@Override
public
Users
selectUsersById
(
int
userid)
{
Connection connection=
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
Users users=
null
;
try
{
connection= JdbcDuridUtill.getConnection();
ps=connection.prepareStatement(
\”select * from users where userid = ?\”
);
ps.setInt(
1
,userid);
rs= ps.executeQuery();
while
(rs.next()){
//手动ORM映射
users=
new
Users();
users.setUserid(rs.getInt(
\”userid\”
));
users.setUsername(rs.getString(
\”username\”
));
users.setUserage(rs.getInt(
\”userage\”
));
}
}
catch
(Exception e){
e.printStackTrace();
//抛出自定义异常信息,解决异常耦合问题
throw
new
ApplicationException(e.getMessage());
}
finally
{
JdbcDuridUtill.closeResource(rs,ps,connection);
}
return
users;
}
}
exception
Application
package
com.itbaizhan.exception;
/**
* 自定义异常,程序运行时异常
*/
public
class
ApplicationException
extends
RuntimeException
{
public
ApplicationException
()
{
}
//实例化异常的时候传递信息
public
ApplicationException
(String msg)
{
super
(msg);
}
//除了传递异常信息,还可以保存异常
public
ApplicationException
(String msg, Throwable throwable)
{
}
}
业务层
在实例化接口实现类的时候类型用接口名:
在一个方法里如果你用到的是另一个对象的类型,那么两个对象就是依赖关系,存在紧耦合问题未来用Spring 框架解决依赖关系
好处
如果下次要添加功能就不需要改
UsersDao ud=new UserDaoImpl();
return null;
这部分代码,直接再写个接口实现类即可
以后都是在业务层做(异常)事务处理,而不是在数据持久层进行异常处理(有异常rollback,没异常commit)
接口
package
com.itbaizhan.service;
import
com.itbaizhan.pojo.Users;
public
interface
UsersService
{
Users
findUsersById
(
int
userid)
;
}
实现类
package
com.itbaizhan.service.impl;
import
com.itbaizhan.dao.UsersDao;
import
com.itbaizhan.dao.impl.UsersDaoImpl;
import
com.itbaizhan.pojo.Users;
import
com.itbaizhan.service.UsersService;
public
class
UsersServiceImpl
implements
UsersService
{
/**
* 根据用户ID查询用户业务
*
@param
userid
*
@return
*/
@Override
public
Users
findUsersById
(
int
userid)
{
UsersDao ud=
new
UsersDaoImpl();
return
ud.selectUsersById(userid);
}
}
web层没有web 组件,就把测试类作为一个外部层的视图,或者控制器的体现
package
com.itbaizhan.web;
import
com.itbaizhan.pojo.Users;
import
com.itbaizhan.service.UsersService;
import
com.itbaizhan.service.impl.UsersServiceImpl;
public
class
Test
{
public
static
void
main
(String[] args)
{
UsersService us=
new
UsersServiceImpl();
Users u=us.findUsersById(
1
);
System.out.println(u);
}
}
封装通用的DML操作
在这个分装后的方法里可以 添加,修改,删除数据
通用型的代码,一定是要抽出来的,作为接口放到外部
多个动态参数放到一个盒子里,所以定义个数组作为传递参数的盒子
用UseDao接口继承BaseDao 接口、用 userDaoImpl 类 继承BaseDaoImpl 类即可
API查看参数个数进行绑定
绑定几个参数就看有几个?
参数在数组里param[i]得对应参数,但?位置为i+1
封装实现类
package
com.itbaizhan.dao.impl;
/**
* 通用接口实现类
*/
import
com.itbaizhan.JdbcDruidUtill;
import
com.itbaizhan.dao.BaseDao;
import
com.itbaizhan.exception.ApplicationException;
import
java.sql.*;
public
class
BaseDaoImpl
implements
BaseDao
{
/**
* 通用DML操作方法
*
@param
sql
*
@param
param
*
@return
*/
@Override
public
int
executeUpdate
(String sql, Object[] param)
{
Connection connection =
null
;
PreparedStatement ps=
null
;
//条数
int
row;
try
{
connection=JdbcDruidUtill.getConnection();
ps=connection.prepareStatement(sql);
//绑定参数
//得到参数个数
ParameterMetaData pd=ps.getParameterMetaData();
for
(
int
i=
0
;i<pd.getParameterCount();i++){
ps.setObject(i+
1
,param[i]);
}
//执行
row=ps.executeUpdate();
}
catch
(Exception e ){
e.printStackTrace();
throw
new
ApplicationException(e.getMessage());
}
finally
{
JdbcDruidUtill.closeResource(ps,connection);
}
return
row;
}
}
在接口里增加个方法
userdao接口
package
com.itbaizhan.dao;
import
com.itbaizhan.pojo.Users;
public
interface
UsersDao
extends
BaseDao
{
//接口里必须实现的方法,省略了public abstract
/**
* 根据用户ID查询用户
*/
Users
selectUsersById
(
int
userid)
;
/**
* 修改用户信息
*/
int
updateUsersById
(Users users)
;
}
因为baseDacImpl 的执行方法被继承了,可以用this . 即可
return this.executeUpdate(sql,param);
userdao实现类
package
com.itbaizhan.dao.impl;
import
com.itbaizhan.JdbcDruidUtill;
import
com.itbaizhan.dao.UsersDao;
import
com.itbaizhan.exception.ApplicationException;
import
com.itbaizhan.pojo.Users;
import
java.sql.PreparedStatement;
import
java.sql.Connection;
import
java.sql.ResultSet;
/**
* 接口实现类
*/
public
class
UsersDaoImpl
extends
BaseDaoImpl
implements
UsersDao
{
/**
* 根据用户ID查询用户
*
@param
userid
*
@return
*/
@Override
public
Users
selectUsersById
(
int
userid)
{
Connection connection=
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
Users users=
null
;
try
{
connection= JdbcDruidUtill.getConnection();
ps=connection.prepareStatement(
\”select * from users where userid = ?\”
);
ps.setInt(
1
,userid);
rs= ps.executeQuery();
while
(rs.next()){
//手动ORM映射
users=
new
Users();
users.setUserid(rs.getInt(
\”userid\”
));
users.setUsername(rs.getString(
\”username\”
));
users.setUserage(rs.getInt(
\”userage\”
));
}
}
catch
(Exception e){
e.printStackTrace();
//抛出自定义异常信息
throw
new
ApplicationException(e.getMessage());
}
finally
{
JdbcDruidUtill.closeResource(rs,ps,connection);
}
return
users;
}
/**
* 修改用户信息
*
@param
users
*
@return
*/
@Override
public
int
updateUsersById
(Users users)
{
//只要准备好sql和参数即可
String sql=
\”update users set userage = ? where userid =? \”
;
//数组初始化方法一
Object[] param ={users.getUserage(),users.getUserid()};
//方法二
// Object[] param=new Object[]{users.getUserage(),users.getUserid()};
return
this
.executeUpdate(sql,param);
}
}
usersservice接口
package
com.itbaizhan.service;
import
com.itbaizhan.pojo.Users;
public
interface
UsersService
{
Users
findUsersById
(
int
userid)
;
int
modifyUsersById
(Users users)
;
}
usersService实现类
添加重载的方法
@Override
public
int
modifyUsersById
(Users users)
{
UsersDao ud=
new
UsersDaoImpl();
return
ud.updateUsersById(users);
}
test2
package
com.itbaizhan.web;
import
com.itbaizhan.pojo.Users;
import
com.itbaizhan.service.UsersService;
import
com.itbaizhan.service.impl.UsersServiceImpl;
public
class
Test2
{
public
static
void
main
(String[] args)
{
UsersService us=
new
UsersServiceImpl();
//用Users来传递参数
Users users=
new
Users();
users.setUserage(
23
);
users.setUserid(
3
);
int
i=us.modifyUsersById(users);
//返回受影响的值
System.out.println(i);
}
}
业务差别就只在sql和参数里了
封装通用的查询语句
查询多了一个映射的问题
有返回值,返回list容器
泛型不确定,要占位符
映射到哪个实体当中(users/boys等表),要把实体的类模版告诉我即class对象告诉我,我可以通过反射把实体对象创建出来,
然后再将结果集映射到实体对象里面
泛型的指定有两种方法
在接口上添加个泛型,未来你在使用这个接口是,你给定接口定义这个接口的时间,给定了类型,那List就啥类型
public interface BaseDao<T> {}
将这个方法变成泛型方法,未来给这个方法什么类型,就是什么类型,在方法的返回值前面再加个泛型符号
<T> List<T> select(String sql ,Object[] param,Class<T> clazz);
将通用方法的API已经创建出来了
package com.itbaizhan.dao;
import
java.util.List;
/**
* 通用接口
*/
public
interface
BaseDao {
/**
* 通用的DML操作方法
*/
//返回DML操作中受影响的条数
int executeUpdate(
String
sql,
Object
[] param);
/**
* 通用查询方法
*/
<T> List<T> select(
String
sql ,
Object
[] param, Class<T> clazz);
}
在BaseDao的实现类里实现抽象方法
得到参数个数绑定参数的过程查询里也要有,因为查询语句里面未来有多个参数的话,也需要向语句的问号当中绑定参数
不同的是下面要 写查询的sql执行语句,还要在外边再创建一个List的对象未来要装结果集
接下来查询结果集,就要在while 里面做ORM的映射了
查询出来的结果集的表也不知道有几列,要看查询语句投影几个列
要先知道投影了几个列,再根据列取里面的内容
API查询语句获取列数
//通过反射先去实例化这个实体类对象
clazz.newInstance();返回泛型对象 T bean=clazz.newInstance();
如果Class没给泛型的话,这个bean 就不能给泛型,而是给默认的Object类型了
第一种方式,通过反射,先去拿这个clazz这个实体类对象去反射它的属性
get declared field 拿到field返回一个field的数组,然后循坏这个数组
在通过这个数组的名字从结果集里get column 去结果集的列的值
还有个硬性要求:实体类的属性名必须要和表的列名相同,不然没法进行通用操作,因为未来要通过这个属性名返回这个列的值
第二种方法,通过第三方工具
阿帕奇Coleman 项目下的一个叫BeanUtill的工具
通过它来完成结果集和实体对象的的属性的映射处理
用rm.getColumnName()获得列的名字,但是你查询出来的表的名字不知道,没办法在括号里输入列的名字,就输入列的位置,从1开始
String columnName =rm.getColumnName(i+1);
//获取列的值
Object value=rs.getObject(columnName);
通过BeanUtil工具类将值映射到对象中
要三个参数
bean是往哪个对象里去做值的映射
name是你当前要往这个对象的哪个属性里映射,属性名和表的列名一样的
value是向这个属性中加入什么值
list.add(bean);最后将bean对象放入list 里
BaseDao实现类
/**
* 通用查询方法
*
@param
sql
*
@param
param
*
@param
clazz
*
@return
*
@param
<T>
*/
@Override
public
<T>
List
<T> select(String sql, Object[] param,
Class
<
T
>
clazz
)
{
Connection connection =
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
List
<T>
list
=
new
ArrayList<>();
try
{
connection=JdbcDruidUtill.getConnection();
ps=connection.prepareStatement(sql);
//绑定参数
//得到参数个数
ParameterMetaData pd=ps.getParameterMetaData();
for
(int i=
0
;i<pd.getParameterCount();i++){
ps.setObject(i+
1
,param[i]);
}
//执行语句
rs=ps.executeQuery();
//查询结果集
//先获取结果集信息
//rs.getMetaData();该方法返回一个ResultSetMetaData类型对象
ResultSetMetaData rm =rs.getMetaData();
while
(rs.next()){
//ORM 映射
//通过反射先去实例化这个实体类对象
T bean=clazz.newInstance();
//实体类的属性名必须要和表的列名相同,不然没法进行通用操作
for
(int i=
0
;i< rm.getColumnCount();i++){
//先得到列名
String columnName =rm.getColumnName(i+
1
);
//获取列的值
Object value=rs.getObject(columnName);
//通过BeanUtil工具类将值映射到对象中
BeanUtils.setProperty(bean,columnName,value);
}
list
.add(bean);
}
}
catch
(
Exception
e ){
e.printStackTrace();
throw
new
ApplicationException(e.getMessage());
}
finally
{
JdbcDruidUtill.closeResource(rs,ps,connection);
}
return
list
;
}
通过继承
usersDao已经具有了查询功能
在接口里再创建一个方法
因为是在UserDao里做的测试,那返回的一定是User类型
UserDao接口
/**
* 根据用户姓名模糊查询
*/
List<Users>
selectUsersByLikeName
(String username)
;
UserDao的实现类
Object[] param=new Object[]{\”%\”+username+\”%\”}; 不用写单引号,因为未来还是要依靠我们写的通用用方法实现参数绑定的
调用继承来的方法
最后一个参数是要放入的对象的模版对象
@Override
public
List<Users> selectUsersByLikeName(
String
username) {
String
sql=
\” select * from users where username like ? \”
;
Object
[] param=
new
Object
[]{
\”%\”
+username+
\”%\”
};
return
this
.select(sql,param,Users.class);
}
Userservice接口
List<Users>
findUsersByLikeName
(String username)
;
UserService实现类
还是先实例化UserDao对象
@Override
public
List<Users>
findUsersByLikeName
(字符串用户名)
{
UsersDao ud=
new
UsersDaoImpl();
返回
ud.selectUsersByLikeName(username);
测试类test3
实例化是逐级调用的
package com.itbaizhan.web;
import
com.itbaizhan.pojo.Users;
import
com.itbaizhan.service.UsersService;
import
com.itbaizhan.service.impl.UsersServiceImpl;
import
java.util.List;
public
class
Test3
{
public
static
void
main
(String[] args)
{
UsersService us=
new
UsersServiceImpl();
List<Users>
list
=us.findUsersByLikeName(
\”l\”
);
//再将list遍历
for
(Users user :
list
){
System.out.println(user);
}
}
}
对象关联关系
关联关系简介
关联关系(Association),是一种拥有的关系,它使一个对象知道另
一个对象的属性和方法。关联可以是双向的,也可以是单向的。在
Java语言中,关联关系一般使用成员变量来实现
users关联了orders
对象的关联关系解决了什么问题
在多表查询时,使用对象关联关系能够更合理的存放查询到的结果
集数据。
关联关系的方向性
1.单向
只在一侧关联了对方。
2.双向
两侧相互关联了对方
创建对象的
创建表
一对多,用外键的方式,多方必用外键
可以通过图形化创建,再比对的方法
创建表
CREATE
TABLE
`orders`
(
`orderid`
int
(
11
)
NOT
NULL
AUTO_INCREMENT,
`orderprice`
float
(
11
,
2
)
DEFAULT
NULL
,
`user_id`
int
(
11
)
DEFAULT
NULL
,
PRIMARY
KEY
(
`orderid`
),
KEY
`orders_fk`
(
`user_id`
),
CONSTRAINT
`orders_fk`
FOREIGN
KEY
(
`user_id`
)
REFERENCES
`users`
(
`userid`
)
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=utf8;
建立三者双向关系
Users
//创建与orders 的关联关系
//如果是一对一的关系,则可以将方法设置为Orders
//但这是一对多的关系,所以用List类型
private
List
<Orders> orders =
new
ArrayList<>();
orders
package
com.itbaizhan.pojo;
import
sun.swing.BakedArrayList;
import
java.util.ArrayList;
import
java.util.List;
public
class
Orders
{
private
int
orderid;
private
double
orderprice;
//不要创建users_id 因为这是用来查询Users对象
//关联Users
//从订单看用户的话,一个订单只对应一个用户
//集合要new 出来,关联的一个对象就不要new出来了
private
Users users;
//关联Items(集合)
private
List<Items> items=
new
ArrayList();
public
int
getOrderid
()
{
return
orderid;
}
public
void
setOrderid
(
int
orderid)
{
this
.orderid = orderid;
}
public
double
getOrderprice
()
{
return
orderprice;
}
public
void
setOrderprice
(
double
orderprice)
{
this
.orderprice = orderprice;
}
public
Users
getUsers
()
{
return
users;
}
public
void
setUsers
(Users users)
{
this
.users = users;
}
public
List<Items>
getItems
()
{
return
items;
}
public
void
setItems
(List<Items> items)
{
this
.items = items;
}
}
items
package
com.itbaizhan.pojo;
import
java.util.ArrayList;
import
java.util.List;
public
class
Items
{
private
int
itemid;
private
String itemname;
private
double
itemprice;
private
int
itemnum;
//关联Orders
private
List<Orders> orders=
new
ArrayList<>();
public
int
getItemid
()
{
return
itemid;
}
public
void
setItemid
(
int
itemid)
{
this
.itemid = itemid;
}
public
String
getItemname
()
{
return
itemname;
}
public
void
setItemname
(String itemname)
{
this
.itemname = itemname;
}
public
double
getItemprice
()
{
return
itemprice;
}
public
void
setItemprice
(
double
itemprice)
{
this
.itemprice = itemprice;
}
public
int
getItemnum
()
{
return
itemnum;
}
public
void
setItemnum
(
int
itemnum)
{
this
.itemnum = itemnum;
}
public
List<Orders>
getOrders
()
{
return
orders;
}
public
void
setOrders
(List<Orders> orders)
{
this
.orders = orders;
}
}
使用关联对象存放查询数据
输入点数据
select
*
from
users
u ,orders o ,order_items oi ,items i
where
u.userid=o.user_id
and
o.orderid=oi.order_id
and
oi.item_id=i.itemid
and
u.userid=
1
根据ID查得返回的一定是Users,Users关联Orders,Items
UserDao
/**
* 查询用户ID为1的用户信息积极他的订单信息
* 以及订单中的所包含的商品信息
*/
Users
selectUsers
(
int
userid)
;
UsersDaoImpl
/**
* 查询用户ID为1的用户信息积极他的订单信息
* 以及订单中的所包含的商品信息
*/
@
Override
public
Users
selectUsers
(
int
userid
)
{
Connection connection=
null
;
PreparedStatement ps=
null
;
ResultSet rs=
null
;
Users users=
new
Users();
try
{
connection= JdbcDruidUtill.getConnection();
ps=connection.prepareStatement(
\”select * from users u ,orders o ,order_items oi ,items i where u.userid=o.user_id and o.orderid=oi.order_id and oi.item_id=i.itemid and u.userid=?\”
);
ps.setInt(
1
,userid);
rs= ps.executeQuery();
while
(rs.next()){
//users对象的ORM映射
users.setUserid(rs.getInt(
\”userid\”
));
users.setUsername(rs.getString(
\”username\”
));
users.setUserage(rs.getInt(
\”userage\”
));
//Orders对象的ORM映射
Orders orders=
new
Orders();
orders.setOrderid(rs.getInt(
\”orderid\”
));
orders.setOrderprice(rs.getDouble(
\”orderprice\”
));
//orders是容器类型
users.getOrders().
add
(orders);
//Items 对象的映射
Items items=
new
Items();
items.setItemid(rs.getInt(
\”itemid\”
));
items.setItemname(rs.getString(
\”itemname\”
));
items.setItemnum(rs.getInt(
\”itemnum\”
));
items.setItemprice(rs.getDouble(
\”itemprice\”
));
orders.getItems().
add
(items);
}
}
catch
(Exception e){
e.printStackTrace();
//抛出自定义异常信息
throw
new
ApplicationException(e.getMessage());
}
finally
{
JdbcDruidUtill.closeResource(rs,ps,connection);
}
return
users;
}
UsersService
Users
findUsers
(
int
userid)
;
UserServixeImpl
@Override
public
Users
findUsers
(
int
userid)
{
UsersDao ud=
new
UsersDaoImpl();
return
ud.selectUsers(userid);
}
test4
package com.itbaizhan.web;
import
com.itbaizhan.pojo.Items;
import
com.itbaizhan.pojo.Orders;
import
com.itbaizhan.pojo.Users;
import
com.itbaizhan.service.UsersService;
import
com.itbaizhan.service.impl.UsersServiceImpl;
import
java.util.List;
public
class
Test4
{
public
static
void main(
String
[] args) {
UsersService
us = new
UsersServiceImpl
();
Users
users = us.findUsers(
1
);
System
.out.
println
(
\”users:\”
+ users.getUserid() +
\” \”
+ users.getUsername() +
\” \”
+ users.getUserage());
List
<
Orders
> list = users.getOrders();
for
(
Orders
orders : list) {
System
.out.
println
(
\”orders:\”
+ orders.getOrderid() +
\” \”
+ orders.getOrderprice());
List
<
Items
> items = orders.getItems();
for
(
Items
item : items) {
System
.out.
println
(
\”Items:\”
+ item.getItemid() +
\” \”
+ item.getItemname() +
\” \”
+ item.getItemprice() +
\” \”
+ item.getItemnum());
}
}
}
}
#以上关于JDBC技术的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91761.html