Jdbc基础知识
一:原生jdbc基础
1.jdbc的本质
本质就是sun公司提供的一套接口规范:接口的子实现类
2.jdbc的相关核心类
1).DriverManager类:1)管理和注册数据库驱动
2)获取数据库连接对象
成员方法
public static void registerDriver(Driver driver):注册驱动
public static Connection getConnection(
String url,
String user,
String password):获取数据库的连接对象
通过创建系统资源发送到数据库的一种url请求
参数1:
url:统一资源定位符
协议://域名或者ip地址:端口号/链接具体地址
jdbc:mysql://localhost:3306/数据库名称
参数2:用户名:root用户
参数3:密码
2).Connection接口:一个连接对象,可用于创建Statement和PreparedStatement
成员方法
有关事务管理相关的方法
void setAutoCommit(boolean autoCommit):设置数据库的提交方式 :
参数为true:表示自动提交
参数为false:表示禁用自动提交
void rollback():事务的回滚
void commit():事务的提交
与数据库执行对象相关方法
Statement createStatement():创建Statement对象,将指定sql发送到数据库中
PreparedStatement prepareStatement(String sql):将
3).Statement接口:一个sql语句对象,用于将sql语句发送给数据库服务器
成员方法
int executeUpdate(String sql) : 通过Statement将静态sql语句发送到数据库中进行操作
执行增删该
ResultSet executeQuery(String sql):执行查询语句select...
4).PreparedStatement接口:预编译处理对象,一个sql语句对象,是Statement的子接口
int executeUpdate():对预编译对象中sql语句直接操作!
5).ResultSet接口:用于封装数据库查询的结果集,返回给客户端的java程序
成员方法
boolean next():判断下一行是否存在有效数据!
XXX getXXX(int columnIndex):根据列的索引值获取表中结果数据:索引值1开始
如果是第一列,则为1
....第二列,则为2
XXX getXXX(String columnLabel):根据列的名称获取
3.环境搭建
1)在项目下新建 lib 文件夹,用于存放 jar 文件。
2)将 mysql 驱动mysql-connector-java-5.1.X复制到项目的 lib 文件夹中。
3)选中 lib 文件夹右键 Add as Libraay,点击 OK。
4.jdbc操作数据库步骤
1)导包:mysql驱动jar包--mysql-connector-java-5.1.37-bin.jar
2)注册驱动:
Class.forName("com.mysql.jdbc.Driver");
3)获取数据库连接对象:
Connection conn=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb_01",
"root",
"root"
);
4)准备sql语句:
String sql="update student set name="小九" where id =2";
5)通过数据库连接对象获取执行对象
Statement stmt=conn.createStatement();
6)执行sql语句
int count=stmt.executeUpdate(sql);
7)处理返回结果
if(count>0){
System.out.println("成功");
}
8)释放资源(先开后关原则)
statement.close();
connection.colse();
代码案例:
publicclassJobsQuery{
publicstaticvoidmain(String[]args){
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接对象
Connection conn=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb_01","root","root\");
//3.获取发送sql语句对象
Statement st=conn.createStatement();
//4.执行SQL语句并接收结果集
ResultSet resultSet=statement.executeQuery("select* from t_jobs");
//5处理结果集
while(resultSet.next()){
//5.1有数据,依据列名获取数据
Stringjob_id=resultSet.getString("job_id");
Stringjob_title=resultSet.getString("job_title")
intmin_salary=resultSet.getInt("min_salary");
intmax_salary=resultSet.getInt("max_salary");
System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);
}
//5.2有数据:根据列的编号获取数据
while(resultSet.next()){
Stringjob_id=resultSet.getString(1);
Stringjob_title=resultSet.getString(2);
intmin_salary=resultSet.getInt(3);
intmax_salary=resultSet.getInt(4);
System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);}
//6.释放资源
rs.close();
st.close();
conn.close();
}
}
}
}
5.statement与PreparedStatement
需求:
键盘录入用户名和密码,模拟用户登录操作
后台---有一张user表:用户表
如果键盘录入的用户名和密码和数据库中user表中用户名和密码一致,登录成功! 否则,"用户名或者密码错误" 存在问题:
什么是 SQL 注入:
用户输入的数据中有 SQL 关键字或语法并且参与了 SQL 语句的编译,导致 SQL 语句编译后的条件含义为true,一直得到正确的结果。这种现象称为 SQL 注入。
使用Statemet对象:存在严重问题:SQL注入: 不安全的行为
select * from user where username = 'sdfsd' and password = 'a' or 'a' = 'a'
用户名和密码完全不一致,依然可以登录成功!
Statement对象:
1.弊端
1)执行效率差
每一次发送sql语句之前,获取Statement
executeUpdate(String sql)
executeQuery(String sql)
2)存在安全漏洞:sql注入 存在字符串拼接导致的!
2.解决: 为了提高执行效率以及防止sql注入
sun公司提供了一个接口:PreparedStatement
将参数化的sql语句先进行预编译(在PreparedStatement对象中 内存中)
参数化的sql语句不存在硬编码的拼接!
3.二者的区别:
执行对象
Statement:
1)操作的静态sql语句
2)通过连接对象获取Statement
3)Statement发送sql到数据库中,操作sql语句效率低,executeUpdate(String sql) executeQuery(String sql)
4)存在字符串拼接,造成sql注入
PreparedStatement:预编译对象
1)通过连接对象获取预编译对象的同时将参数化的sql发送数据库进行预编译!
2)相对Statement对象,执行效率高
3)能够有效防止sql注入
1)PreparedStatemet实现用户登录,注册操作代码体现
public class StatementTest{
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=isLogin(username,password);
if(flag){
System.out.println("恭喜你,登录成功!");
}
else{
System.out.println("登录失败,您的用户名或密码不正确");
}
}
//登录页面实现方法
private static boolean isLogin(String username,String password){
Connection conn=null;
PreparedStatement stmt=null;
ResultSet rs=null;
try{
//获取数据库连接对象
conn=JdbcUtils.getconnection();
//准备SQL语句(通过用户名和密码查询用户---查询某一条件记录---如果有内容:存在)
String sql="select *from user where username=? and password=?";
//将参数化的sql语句发送数据库进行预编译
stmt=conn.prepareStatement(sql);
//给占位符赋值void setXXX(nt parameterIndex,实际参数)
//参数1:?是第几个占位符
//参数2:实际参数
stmt.setString(1,username);
stmt.setString(2,password);
//执行查询更新
rs=stmt.executQuery();
return rs.next();
}catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs, stmt, conn);
}
return false
}
}
6.PreparedStatement执行DML和DQL的基本操作是什么
1)注册驱动
2)获取数据库连接
3)准备参数化的sql
4)通过连接对象获取预编译对象
连接对象.prepareStatement(String sql)---->PreparedStatement
5)参数赋值
通过setXXX(占位符的索引值,实际参数) 对占位符号进行赋值
6)执行
int execueteUpdate()
ResultSet executeQuery()
查询的:还需要遍历结果集
二.针对原生jdbc进行工具类的封装
1.工具类的封装
1)封装步骤
静态代码块static{
将jdbc.properties配置文件加载到属性集合类中Properties
获取里面参数信息
driverClass
user
url
password
注册驱动
}
封装获取连接对象的方法getConnection()
封装释放资源的方法close(ResultSet rs,Statement stmt,Connection conn) ;
close(Statement stmt,Connection conn)
2).代码体现
public class JdbcUtils{
//成员变量的位置
public static String url = null ;
public static String user = null ;
public static String password = null ;
//提供一个属性
public static String driverClass = null
//提供一个静态代码块(随类的加载而加载)
//在加载JdbcUtils类的时候,静态代码中的内容优先执行
static {
try {
//创建一个属性集合类对象
Properties prop = new Properties() ;
//将jdbc.properties的配置文件内容加载到prop属性集合中
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties") ;
prop.load(inputStream);
//通过prop的键获取值
url = prop.getProperty("url") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
driverClass = prop.getProperty("driverClass") ;
//注册驱动
Class.forName(driverClass) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//构造方法私有化
private JdbcUtils() {}
//静态功能
//获取连接对象--封装
public static Connection getConnection() {
//需要通过驱动管理类获取 DriverManager
//三个参数需要放在配置文件 xx.properites----将三个参数:jdbc.properties
try {
Connection conn = DriverManager.getConnection(url, user, password);
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭资源---封装
//针对DQL语句进行操作:释放资源
public static void close(ResultSet rs,Statement stmt,Connection conn) {
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();
}
}
}
//针对DDL/DML:增删改 释放资源
public static void close(Statement stmt,Connection conn) {
close(null, stmt, conn);
}
}
2.jdbc.properties配置文件
url=jdbc:mysql://localhost
user=root
password=root
driverClass=com.mysql.jdbc.Driver
3.测试案例(原生jdbc工具类进行增删查改)
1)需求
1.创建一个部门表dept,提供部门编号,部门名称,部门位置,使用原生JDBC(封装成工具类的形式)对dept表进行操作该
a)需要通过外置属性文件进行读取数据库 连接信息
b)分页展示dept表的数据信息,每页展示2条,并将数据封装到List<Dept>中(参数为每页条数和展示的页码)
c)向dept表中插入50,"DEVELOPMENT","China"(参数为dept对象)
d)删除dept表中50号部门的信息(参数为部门编号)
e)通过部门编号查询部门
f)查询全部
7)查询总记录数
2.代码体现
public class DeptDaoImpl{
//插入操作
public static void addDept(Dept dept){
Connecton conn=null;
PrepareStatemet stmt=null;
try{
conn=JdbcUtils.getConnection();
String sql="insret into dept (dept_id,dept_name,dept_loc) values (?,?,?)";
stmt=conn.prepareStatement(sql);
stmt.setInt(1,dept.dept_id);
stmt.setString(2,dept.dept_name);
stmt.setString(3,dept.dept_loc);
int count=stmt.executeUpdate();
if(count>0){
System.out.println("数据插入成功");
}
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtils.close(conn, pstmt);
}
}
//删除操作
public static void delete(int dept_id){
Connection conn=null;
PreparedStatement stmt=null;
try{
conn=JdbcUtils.getConnection();
String sql="delete from dept where dept_id =?";
stmt=conn.prepareStatement(sql);
stmt.setInt(1,dept_id);
int count=stmt.executeUpdate();
if(count>0){
System.out.println(数据删除成功!);
}
}
}
//通过id查询
public static Dept getDept(int deptid){
Connection conn=null;
PreparedStatement stmt=null;
ResultSet rs=null;
Dept dept=new Dept;
try{
conn=JdbcUtils.getConnection();
String sql="select *from dept where dept_id=?";
stmt=conn.prepareStatement(sql);
stmt.setInt(1,deptid);
rs=stmt.executeQuery();
while(rs.next()){
int id=rs.getInt("id");
int dept_id=rs.getInt("dept_id");
String dept_name=rs.getString("dept_name");
String dept_loc=rs.getString("dept_loc");
d.setDept_id(dept_id);
d.setId(id);
d.setDept_name(dept_name);
d.setDept_loc(dept_loc);
}
return d;
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.close(rs, conn, pstmt);
}
return null;}
}
//分页展示dept表的数据信息,每页展示2条,并将数据封装到List<Dept>中
public static void findAll(int tiao,int ye){
Connection conn=null;
ResultSet rs=null;
PreparedStatement pstmt=null;
Dept dept=null;
ArrayList<Dept> list=new ArrayList<Dept>();
try {
conn=JdbcUtils.getConnection();
String sql="select *from dept limit ?,?";
pstmt=conn.prepareStatement(sql);
int hang=(ye-1)*tiao;
pstmt.setInt(1, hang);
pstmt.setInt(2, ye);
rs=pstmt.executeQuery();
while(rs.next()) {
dept=new Dept();
//获取数据
int id=rs.getInt("id");
int dept_id=rs.getInt("dept_id");
String dept_name=rs.getString("dept_name");
String dept_loc=rs.getString("dept_loc");
//将数据封装到Dept对象中
dept.setDept_id(dept_id);
dept.setId(id);
dept.setDept_name(dept_name);
dept.setDept_loc(dept_loc);
list.add(dept);
}
if(list!=null) {
for(Dept d:list) {
System.out.println(d);
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtils.close(rs, conn, pstmt);
}
}
//输出记录总数
public long getCount(){
Connection conn=null;
PreparedStatement stmt=null;
ResultSet rs1=null;
List<User> list=null;
Dept dept=null;
try{
conn=JdbcUtils.getConnection();
String sql="select *from dept ";
stmt=conn.prepareStstement(sql);
rs=stmt.executeQuery();
while(rs.next()){
dept=new Dept();
//获取数据
int id=rs.getInt("id");
int dept_id=rs.getInt("dept_id");
String dept_name=rs.getString("dept_name");
String dept_loc=rs.getString("dept_loc");
//将数据封装到Dept对象中
dept.setDept_id(dept_id);
dept.setId(id);
dept.setDept_name(dept_name);
dept.setDept_loc(dept_loc);
list.add(dept);
}return list.size;
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JdbcUtils.close(rs1, stmt, conn);
}
return 0
}
}
}
三:连接池
连接池 :
连接对象可以重复利用(固定的 /可重用的)-----使用完毕之后会再次归还到连接池中
自动参与连接
sun提供了接口 java.sql.DataSource:物理数据源的链接----代替了DriverManager工具(jdbc的一组服务)
成员方法
Connection getConnection();
驱动类的厂商提供:
c3p0核心jar包 源码包 --- 日志记录
druid核心jar包 源码包
dbcp核心jar包...
(一).c3p0连接池
c3p0连接池----相关的jar包
1)导入jar包
c3p0-0.9.5.2.jar -核心jar包
mchange-commons-java-0.2.12.jar c3p0的依赖包
2)需要将c3p0核心配置文件存储在src目录下 自动读取
两种方式
c3p0.properties
c3p0-config.xml ----- spring,springmvc,mybatis主流框架xml文件配置方式
3)配置文件中提了一些
基本参数
driverClass:数据库驱动实现
jdbcUrl 连接特定的数据库
user用户名
password 密码
连接池的参数信息
initialPoolSize :初始化连接数量
maxPoolSize:最大连接数量
checkoutTimeout:超时时间 单位为毫秒 如果超过最大连接数量,在指定时间连接不上,就会出现问题了
(二).druid连接池
1.druid相关知识
druid连接池----相关的jar包
1) 导入核心jar包
druid-1.0.9.jar --- DruidDataSource
2)在src目录执行核心配置文件
jdbc.properites (名称可以随便起)
有一些基本参数信息
连接池的信息
druid里面内置的属性名字
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb_02
username=root
password=123456
连接池的默认配置信息
initialSize=5 初始化连接数量5
maxActive=10 最大激活数量10个
maxWait=3000 最大的等待时间
3)获取连接对象呢?
使DruidDataSourceFactory:德鲁伊的物理数据源的工厂类
静态方法
2.Druid 连接池配置文件(druid.propertise)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb_05
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
3.Druid工具类
封装工具类
1)使用连接池获取连接对象 ----Druid连接池
DruidDataSourceFactory.createDataSource(Properties prop)--->javax.sql.DataSource 2)封装获取连接的方法
mygetConnection()-----DataSource对象可以调用getConnection()
3)释放资源
public class MyJdbcUtils {
//成员位置声明
private static DruidDataSource ds ; //直接使用具体的子实现类:DruidDataSource
private MyJdbcUtils() {}
static {
try {
//创建一个属性集合类对象
Properties prop = new Properties() ;
//读取druid.properties 核心配置文件
InputStream inputStream = MyJdbcUtils.class.
getClassLoader().getResourceAsStream("druid.properties") ;
//加载到prop
prop.load(inputStream);
//通过Druid连接池提供 的工厂类创建物理数据源DataSource
ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop) ;
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取数据库连接
public static Connection getConnection() {
Connection conn = null ;
try {
conn = ds.getConnection() ;
return conn ;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null ;
}
//获取DataSource的方法
public static DataSource getDataSource() {
return ds;
}
//释放资源的方法
public static void close(ResultSet rs,PreparedStatement 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 close(PreparedStatement stmt,Connection conn) {
close(null, stmt, conn);
}
//开启事务
/*
public static void startTransaction(Connection conn) {
if(conn!=null) {
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
*/
4.Druid包含的接口和类
ResultSetHandler接口:转换类型接口
BeanHandler类:实现类,把一条记录转换成对象
BeanListHandler类:实现类,把多条记录转换成List集合。
ScalarHandler类:实现类,适合获取一行一列的数据。
QueryRunner:执行sql语句的类增、删、改:update();查询:query();
5.Druid常量池工具实现数据库的增删查改
public class UserDaoImpl{
//添加数据
public void addUser(User user) throws SQLException{
//创建执行对象
QueryRunner qr=new QueryRunner(MyJdbcUtils.getDataSource());
//准备sql语句:必须是参数化sql
String sql="insert into user() values(?,?,?,?)"
//执行更新
int count=qr.update(sql,
user.getName(),
user.getGender(),
user.getAddress(),
user.getPhone());
if(count >0){
System.out.println("数据插入成功");
}
}
//删除数据
public void deleteUser(int id){
try{
QueryRunner qr=new QueryRunner(MyJdbcUtils.getDataSource());
String sql="delete from user where id = ?";
int count = qr.update(sql,id);
if(count>0){
System.out.println("数据删除成功");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//查询单个数据
public User getUserById(intid){
try{
QueryRunner qr=new QueryRunner(MyJdbcUtils.getDataSource());
String sql="select * from user where id id=?";
User user=null;
user=qr.query(sql,new BeanHandler<User>(User.class),id);
System.out.println(user);
retirn user;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//查询所有数据
public List<User> findAll(){
List<User> list=new arrayList<User>();
try{
QueryRunner qr=new QueryRunner(MyJdbcUtils.getDataSource());
String sql="select * from";
list=qr.query(sql,new BeandListHandler<User>(User.class));
for(User user:list){
System.out.println(list);
}
return list;
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//查询记录总数
public long count(){
List<User> list=null;
try{
QueryRunner qr=new QueryRunner(MyJdbcUtils.getDataSource());
String sql="select count(id) from user";
long count=qr.query(sql,new ScalarHandleder<User>());
return count;
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
}