JDBC从零开始的保姆级教程!!!
- JAVA与数据库的连接方式
- JDBC体系结构
- JDBC程序编写步骤
- 获取数据库连接方式一
- 数据库连接方式二
- 数据库连接的方式三
- 数据库连接方式四
- 数据库连接方式五---final版本
-
- final版的好处
- 操作和访问数据库
-
- DriverManger : 驱动管理对象
- Connection :数据库连接对象
- Statement : 执行sql的对象
- ResultSet: 结果集对象,封装查询结果
- JDBC工具类----JDBCUtils
- 利用工具类来实现一个检测登陆是否成功的案例
-
- PreparedStatement : 执行sql的对象,避免SQL注入问题
- JDBC管理事务
- 数据库连接池
-
- 连接池实现
- c3p0连接池
- Druid连接池
- 工具类
- JDBC数据的批处理操作
- Spring的Template
-
- 执行DML语句
- 执行DQL语句
- 注意:
JAVA与数据库的连接方式
JDBC体系结构
JDBC程序编写步骤
获取数据库连接方式一
import java.sql.*;
import java.util.Properties;
public class MAIN
{
public static void main(String[] args) throws ClassNotFoundException, SQLException
{
//获取driver的实现类对象
Driver driver=new com.mysql.jdbc.Driver();
//jbdc:mysql :协议
//localhost: ip地址
// 3306: 默认mysql的端口号
//test1: test1数据库
String url="jdbc:mysql://localhost:3306/test1";
//将用户名和密码封装在properties中
Properties info=new Properties();
info.setProperty("user","root");
info.setProperty("password","126433");
Connection conn=driver.connect(url,info);
System.out.println(conn);
}
}
数据库连接方式二
对方式一的迭代,避免第三方的api,使得程序有更好的可移植性
import java.sql.*;
import java.util.Properties;
public class MAIN
{
public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
//1.获取Driver实现类对象,使用反射
Class clazz=Class.forName("com.mysql.jdbc.Driver");
Driver driver=(Driver)clazz.newInstance();
String url="jdbc:mysql://localhost:3306/test1";
Properties info=new Properties();
info.setProperty("user","root");
info.setProperty("password","126433");
Connection conn=driver.connect(url,info);
System.out.println(conn);
}
}
数据库连接的方式三
使用DriverManger替换Driver
import java.sql.*;
import java.util.Properties;
public class MAIN
{
public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
//1.提供另外三个连接的基本信息
String url="jdbc:mysql://localhost:3306/test1";
String user="root";
String password="126433";
//2.获取Driver实现类对象,使用反射
Class clazz=Class.forName("com.mysql.jdbc.Driver");
Driver driver=(Driver)clazz.newInstance();
//注册驱动
DriverManager.registerDriver(driver);
//获取连接
Connection conn=DriverManager.getConnection(url,user,password);
System.out.println(conn);
}
}
数据库连接方式四
可以只是加载驱动,而非显示的注册驱动了
import java.sql.*;
import java.util.Properties;
public class MAIN
{
public static void main(String[] args) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
//1.提供另外三个连接的基本信息
String url="jdbc:mysql://localhost:3306/test1";
String user="root";
String password="126433";
//2.加载Driver
Class clazz=Class.forName("com.mysql.jdbc.Driver");
//相较于方式三,可以省略如下的操作:
/* Driver driver=(Driver)clazz.newInstance();
//注册驱动
DriverManager.registerDriver(driver);*/
//获取连接
Connection conn=DriverManager.getConnection(url,user,password);
System.out.println(conn);
}
}
为什么可以省略呢?
因为在mysql的Driver实现类中,静态代码块声明了如下的操作:
数据库连接方式五—final版本
将数据库连接需要的四个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
配置文件:
user=root
password=126433
url=jdbc:mysql://localhost:3306/test1
driverClass=com.jdbc.mysql.Driver
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class MAIN
{
public static void main(String[] args) throws Exception{
//MAIN是当前的类
InputStream is=MAIN.class.getClassLoader().getResourceAsStream("jdbc.properities");
Properties pros=new Properties();
pros.load(is);
String user=pros.getProperty("user");
String password=pros.getProperty("password");
String url=pros.getProperty("url");
String driverClass=pros.getProperty("driverClass");
//加载驱动
Class.forName(driverClass);
//获取连接
Connection conn=DriverManager.getConnection(url,user,password);
System.out.println(conn);
}
}
final版的好处
实现了数据和代码的分离,实现了解耦
如果需要修改配置文件信息,可以避免程序重新打包
操作和访问数据库
DriverManger : 驱动管理对象
功能1:
功能2:
演示:
public static void main(String[] args) throws Exception {
//1.导入驱动jar包
//2.注册驱动
//java5版本后可以省略下面这行代码
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象
//Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test1","root","126433");
Connection conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//4.定义sql语句
//注意: 嵌套字符串,外双里单
//这里被双引号包裹的sql语句结尾不用加分号
String sql="update depart set name='大忽悠总裁办' where wID=105";
//5.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//6.执行sql
int count=stmt.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
stmt.close();
conn.close();
}
Connection :数据库连接对象
Statement : 执行sql的对象
DDL语句默认返回0
insert语句练习:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//2.定义sql语句
String sql="INSERT INTO depart VALUES(110,'小朋友副总裁办')";
try {
//3.获取connection对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//4.获取sql对象,执行Statement
stmt=conn.createStatement();
//5.执行sql
int count=stmt.executeUpdate(sql);
if(count>0)
System.out.println("添加成功!!");
else
System.out.println("添加失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
//避免空指针异常
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
update语句练习:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获取connection对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//3.定义sql语句
String sql="update depart set name='大忽悠和小朋友工作室' where wID=101";
//4.获取sql对象
stmt=conn.createStatement();
//5.执行sql语句
int count=stmt.executeUpdate(sql);
if(count>0)
System.out.println("修改成功");
else
System.out.println("修改失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
delete语句练习:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获取connection对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//3.定义sql语句
String sql="delete from depart where name like '%后%'";
//4.获取sql对象
stmt=conn.createStatement();
//5.执行sql语句
int count=stmt.executeUpdate(sql);
if(count>0)
System.out.println("删除成功");
else
System.out.println("删除失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
DDL语句之建表练习:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获取connection对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//3.定义sql语句
String sql="create table newDepart(newWID int primary key,newDepartName varchar(20))";
//4.获取sql对象
stmt=conn.createStatement();
//5.执行sql语句
int count=stmt.executeUpdate(sql);
System.out.println("DDL语句默认返回: "+count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
ResultSet: 结果集对象,封装查询结果
演示:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获取conncetion对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//3.定义sql语句---查询语句
String sql="select *from depart";
//4.获取执行sql的对象
stmt=conn.createStatement();
//5.执行sql语句---返回一个查询到的结果集
rs=stmt.executeQuery(sql);
//6.处理结果
//6.1让游标向下移动一行
rs.next();
//6.2获取资源
int wID=rs.getInt(1);
String name=rs.getString("name");
System.out.println("查询到的部门编号:"+wID+" 查询到部门名称:"+name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
//最后打开的先释放
try {
if(rs!=null)
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(stmt!=null)
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(conn!=null)
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
注意:
查询所有记录的正确演示:
public class newMain {
public static void main(String[] args)
{
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
//1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.获取conncetion对象
conn= DriverManager.getConnection("jdbc:mysql:///test1","root","126433");
//3.定义sql语句---查询语句
String sql="select *from depart";
//4.获取执行sql的对象
stmt=conn.createStatement();
//5.执行sql语句---返回一个查询到的结果集
rs=stmt.executeQuery(sql);
//6.处理结果
//循环判断游标是否是最后一行的末尾
while(rs.next())
{
//6.2获取资源
int wID=rs.getInt(1);
String name=rs.getString("name");
System.out.println("查询到的部门编号:"+wID+" 查询到部门名称:"+name);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//7.释放资源
//最后打开的先释放
try {
if(rs!=null)
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(stmt!=null)
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(conn!=null)
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
JDBC工具类----JDBCUtils
目的:简化书写
分析:
- 注册驱动也抽取一下
- 抽取一个方法来获取连接对象
需求:不想传递参数,还要保证工具类的通用性
解决: 配置文件
jdbc.properties
url=
user=
password= - 抽取一个方法来释放资源
代码演示:
JDBCUtil工具类:
package tuil;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/*
JDBC工具类
* */
public class JDBCUtil
{
private static String url;
private static String user;
private static String password;
private static String driver;
//文件的读取只需要读取一次即可拿到配置文件中的信息
//使用静态代码块--->随着类的加载而首选加载,并且只执行一次
static {
//读取资源文件,获取值
//1.创建Properties集合类
Properties pro=new Properties();
//2.加载文件
try {
//获取src下文件路径的方法----->ClassLoader 类加载器
//作用: (1)加载字节码文件进内存
//(2):获取src下资源文件的路径
ClassLoader cl=JDBCUtil.class.getClassLoader();
//返回一个URL对象,URL:统一资源定位符,可以用来获取文件的绝对路径
URL res=cl.getResource("jdbc.properties");
String path=res.getPath();
pro.load(new FileReader(path));
} catch (IOException e) {
e.printStackTrace();
}
//3.获取数据,赋值
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");
//4.注册驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//设置所有方法为静态的,方便调用
//1.获取连接,返回连接对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//2.释放资源
public static void close(Statement stmt,Connection conn)
{
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//释放资源的重载版本
public static void close(ResultSet rs,Statement stmt, Connection conn)
{
if(rs!=null)
{
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
jdbc.properties配置文件:
url=jdbc:mysql:///test1
user=root
password=126433
driver=com.mysql.jdbc.Driver
newMian测试主类:
import tuil.JDBCUtil;
import java.sql.*;
public class newMain {
public static void main(String[] args)
{
try {
Connection conn=JDBCUtil.getConnection();
Statement stmt=conn.createStatement();
String sql="update depart set name='大忽悠研发部' where wID=103";
stmt.executeUpdate(sql);
JDBCUtil.close(stmt,conn);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
结果演示:
利用工具类来实现一个检测登陆是否成功的案例
login类
package tuil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class loginMain {
public static void main(String[] args)
{
//1.键盘录入,接收用户名和密码
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名: ");
String username=sc.next();
System.out.println("请输入密码: ");
String password=sc.next();
//2.调用方法
boolean flag=new loginMain().login(username,password);
if(flag)
System.out.println("登陆成功");
else
System.out.println("登陆失败");
}
/*
* 登陆方法
* */
public boolean login(String userName,String password) {
if(userName==null||password==null)
return false;
//连接数据库判断是否登陆成功
//1.获取连接
Connection conn= null;
Statement stmt=null;
ResultSet res=null;
try {
conn = JDBCUtil.getConnection();
//2.定义sql
String sql="select * from login where Username='"+userName+"'and password='"+password+"'";
//3.获取执行sql的对象
stmt=conn.createStatement();
//4.执行查询
res=stmt.executeQuery(sql);
//5.判断
return res.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDBCUtil.close(res,stmt,conn);
}
return false;
}
}
配置文件信息修改和对应数据库信息展示
执行效果演示
PreparedStatement : 执行sql的对象,避免SQL注入问题
PreparedStatement的父类是Statement
检测登陆案例SQL注入问题修正版本
只针对login类进行代码处理:
package tuil;
import java.sql.*;
import java.util.Scanner;
public class loginMain {
public static void main(String[] args)
{
//1.键盘录入,接收用户名和密码
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名: ");
String username=sc.next();
System.out.println("请输入密码: ");
String password=sc.next();
//2.调用方法
boolean flag=new loginMain().login(username,password);
if(flag)
System.out.println("登陆成功");
else
System.out.println("登陆失败");
}
/*
* 登陆方法
* */
public boolean login(String userName,String password) {
if(userName==null||password==null)
return false;
//连接数据库判断是否登陆成功
//1.获取连接
Connection conn= null;
PreparedStatement pstmt=null;
ResultSet res=null;
try {
conn = JDBCUtil.getConnection();
//2.定义sql
String sql="select * from login where Username= ? and password= ?";
//3.获取执行sql的对象
pstmt=conn.prepareStatement(sql);
//给?赋值
pstmt.setString(1,userName);
pstmt.setString(2,password);
//4.执行查询---不需要传递sql,不然就调用其父类的函数了
res=pstmt.executeQuery();
//5.判断
return res.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//父类指针指向子类引用
JDBCUtil.close(res,pstmt,conn);
}
return false;
}
}
JDBC管理事务
演示为什么要使用事务,这里使用一个转账案例作为演示:
数据库环境搭建:
大忽悠转账给小朋友500:
正常没有出现异常的情况,转账成功
package tuil;
import java.sql.*;
import java.util.Scanner;
public class loginMain {
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.println("转账者:");
String Giver=sc.nextLine();
System.out.println("收款者:");
String Revicer=sc.nextLine();
System.out.println("转账金额:");
int money=0;
if(sc.hasNextInt())
money=sc.nextInt();
boolean flag=new loginMain().giveMoney(Giver,Revicer,money);
if(flag)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
/*
* 大忽悠转账给小朋友500块
* */
public boolean giveMoney(String Giver,String Revicer,int money) {
if(Giver==null||Revicer==null||money<0)
return false;
//连接数据库判断是否登陆成功
//1.获取连接
Connection conn= null;
PreparedStatement pstmt1=null;
PreparedStatement pstmt2=null;
try {
conn = JDBCUtil.getConnection();
//2.定义sql
String sql1="update login set money=money-? where name= ?";
String sql2="update login set money=money+? where name= ?";
//3.获取执行sql的对象
pstmt1=conn.prepareStatement(sql1);
pstmt2=conn.prepareStatement(sql2);
//给?赋值
pstmt1.setInt(1,500);
pstmt1.setString(2,"大忽悠");
pstmt2.setInt(1,500);
pstmt2.setString(2,"小朋友");
//4.执行
pstmt1.executeUpdate();
pstmt2.executeUpdate();
return true;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//父类指针指向子类引用
JDBCUtil.close(pstmt1,conn);
JDBCUtil.close(pstmt2,conn);
}
return false;
}
}
出现异常的情况下,转账到一半就会终止,得到的结果会出现问题
//4.执行
pstmt1.executeUpdate();
//异常的出现
String s=null;
s.getBytes(StandardCharsets.UTF_8);
pstmt2.executeUpdate();
这个时候,转账出现问题,需要通过事务来进行解决
package tuil;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.Scanner;
public class loginMain {
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.println("转账者:");
String Giver=sc.nextLine();
System.out.println("收款者:");
String Revicer=sc.nextLine();
System.out.println("转账金额:");
int money=0;
if(sc.hasNextInt())
money=sc.nextInt();
boolean flag=new loginMain().giveMoney(Giver,Revicer,money);
if(flag)
System.out.println("转账成功");
else
System.out.println("转账失败");
}
/*
* 大忽悠转账给小朋友500块
* */
public boolean giveMoney(String Giver,String Revicer,int money) {
if(Giver==null||Revicer==null||money<0)
return false;
//连接数据库判断是否登陆成功
//1.获取连接
Connection conn= null;
PreparedStatement pstmt1=null;
PreparedStatement pstmt2=null;
try {
conn = JDBCUtil.getConnection();
//开启事务
conn.setAutoCommit(false);
//2.定义sql
String sql1="update login set money=money-? where name= ?";
String sql2="update login set money=money+? where name= ?";
//3.获取执行sql的对象
pstmt1=conn.prepareStatement(sql1);
pstmt2=conn.prepareStatement(sql2);
//给?赋值
pstmt1.setInt(1,500);
pstmt1.setString(2,"大忽悠");
pstmt2.setInt(1,500);
pstmt2.setString(2,"小朋友");
//4.执行
pstmt1.executeUpdate();
//异常的出现
String s=null;
s.getBytes(StandardCharsets.UTF_8);
pstmt2.executeUpdate();
//结束事务
conn.commit();
return true;
} catch (SQLException throwables) {
//事务进行回滚
try {
if(conn!=null)
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
//父类指针指向子类引用
JDBCUtil.close(pstmt1,conn);
JDBCUtil.close(pstmt2,conn);
}
return false;
}
}
开启事务后,一旦出现异常,可以通过事务回滚来恢复被修改的数据
数据库连接池
连接池实现
c3p0连接池
jar包的导入这里就不再多说了
这里配置文件中还需要对一些数据进行修改
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test1</property>
<property name="user">root</property>
<property name="password">126433</property>
<!-- 连接池参数 -->
<!-- 初始化申请的连接数量 -->
<property name="initialPoolSize">5</property>
<!-- 最大的连接数量 -->
<property name="maxPoolSize">10</property>
<!-- 超时时间 -->
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
主类连接测试:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class main {
public static void main(String[] args) throws SQLException {
//1.创建数据库连接池对象
DataSource ds=new ComboPooledDataSource();
//2.获取连接对象
Connection conn=ds.getConnection();
//3.打印
System.out.println(conn);
}
}
获取DataSource,使用指定名称配置,如果不传入字符串,指定默认第一个配置
public class main {
public static void main(String[] args) throws SQLException {
//1.获取DataSource,使用指定名称配置
DataSource ds=new ComboPooledDataSource("dhy");
//2.获取连接对象
Connection conn=ds.getConnection();
//3.打印
System.out.println(conn);
}
}
同时使用多个连接和归还连接
这里原本最多只能有8个连接,我们使用了9次连接,因为其中当i=3时,我们归还了一个连接,不然会报错
public class main {
public static void main(String[] args) throws SQLException {
//1.获取DataSource,使用指定名称配置
DataSource ds=new ComboPooledDataSource("dhy");
//2.获取连接对象
for(int i=0;i<9;i++)
{
Connection conn=ds.getConnection();
System.out.println(i+":"+conn);
if(i==3)//归还连接到连接池
conn.close();
}
Druid连接池
配置文件:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test1
username=root
password=126433
#初始化连接数量
initialSize=5
#最大连接数
maxActive=10
#最大等待时间
maxWait=3000
连接代码演示:
public class main {
public static void main(String[] args) throws Exception {
//加载配置文件
Properties pro=new Properties();
InputStream is=main.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//获取连接池对象
DataSource ds=DruidDataSourceFactory.createDataSource(pro);
//获取连接
Connection conn=ds.getConnection();
System.out.println(conn);
}
}
工具类
工具类完整代码:
package Utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
//1.定义成员变量
private static DataSource ds;
static {
try {
//1.加载配置文件
Properties pro=new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
ds= DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//释放资源
public static void close(ResultSet res,Statement stmt, Connection conn)
{
if(res!=null)
{
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt!=null)
{
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Statement stmt, Connection conn)
{
close(null,stmt,conn);
}
public static DataSource getDataSource()
{
return ds;
}
}
使用新的工具类进行测试:
package Utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class testDemo1 {
public static void main(String[] args)
{
Connection conn=null;
PreparedStatement pstmt=null;
try
{
//1.获取连接
conn=JDBCUtils.getConnection();
//2.定义sql
String sql="insert into depart values(?,?)";
//3.获取pstmt对象
pstmt=conn.prepareStatement(sql);
//4.给?赋值
pstmt.setInt(1,520);
pstmt.setString(2,"大忽悠和小朋友婚姻办");
//5.执行sql语句
int count=pstmt.executeUpdate();
System.out.println("影响语句条数:"+count);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(pstmt,conn);
}
}
}
JDBC数据的批处理操作
默认情况下mysql的批处理没有开启,我们需要在url后面拼接一个参数即可
所要拼接的参数:
rewriteBatchedStatements=true
演示:
package Utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class testDemo1 {
public static void main(String[] args)
{
//记录耗费的时间
long begin=System.currentTimeMillis();
Connection conn=null;
PreparedStatement pstmt=null;
try
{
//1.获取连接
conn=JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//2.定义sql
String sql="insert into boy values(null,?)";
//3.获取pstmt对象
pstmt=conn.prepareStatement(sql);
//4.给?赋值
for(int i=1;i<=10000;i++)
{
pstmt.setString(1,"小朋友"+i+"号");
//添加到批处理
pstmt.addBatch();
//注意问题: 批处理里面写的sql语句,会被先放到内存中
//为了防止内存溢出,我们可以等到批处理攒到1000条语句的时候,执行一次批处理
//然后清空批处理
if(i%500==0)
{
//执行批处理
pstmt.executeBatch();
//执行完后内容还在内存上,我们还需要清空批处理
pstmt.clearBatch();
}
}
// 将剩下的未处理命令发送给数据库
pstmt.executeBatch();
//手动提交事务
conn.commit();
} catch (SQLException throwables) {
//事务进行回滚
try {
if(conn!=null)
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(pstmt,conn);
}
long end=System.currentTimeMillis();
System.out.println("插入一万条记录耗费的时间为:"+(end-begin));
}
}
因为prepareStatement会对sql语句进行预编译,因此在执行样式类似的sql语句时,会很大优势,不需要对每一天sql都进行编译
Spring的Template
执行DML语句
修改表记录演示:
```java
package Utils;
import org.springframework.jdbc.core.JdbcTemplate;
public class testDemo1 {
public static void main(String[] args)
{
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
//调用方法
String sql="UPDATE depart SET `name`='大忽悠和小朋友会计部' WHERE wID= ?";
//返回影响的行数
int count=template.update(sql,102);//这里如果有多个?,那么传入的参数顺序和?一一对应
System.out.println("影响的行数:"+count);
}
}
添加记录演示:
public class testDemo2 {
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
//junit单元测试,让方法能够独立运行
@Test
public void test()
{
//插入一条记录
//1.获取datasource对象
String sql="insert into boy(name) values(?)";
int count=template.update(sql,"大忽悠");
System.out.println(count);
}
}
删除记录演示:
public class testDemo2 {
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
//junit单元测试,让方法能够独立运行
@Test
public void test()
{
//插入一条记录
//1.获取datasource对象
String sql="delete from boy where name= ?";
int count=template.update(sql,"大忽悠");
System.out.println(count);
}
}
执行DQL语句
查询dno为3的员工记录:
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
String sql="select * from employee where dno= ?";
//将查询结果封装为map集合
Map<String,Object> map=template.queryForMap(sql,3);
System.out.println(map);
说明这个方法查询的结果集长度只能是1
因为键值不能重复,而查询到的数据的列名被封装为了键值,这样在查询多条记录时,键值必定重复
查询dno=2的记录,将其封装为list集合:
可以用来查询多条记录,原理是将每一条记录都封装为一个map集合,最后将map装载到list里面
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
String sql="select * from employee where dno= ?";
//将查询结果封装为map集合
List<Map<String, Object>> map=template.queryForList(sql,3);
System.out.println(map);
查询所有记录,将其封装为Emp对象的Lsit集合:
class Emp{
public int did;
public String dname;
@Override
public String toString() {
return "Emp{" +
"did=" + did +
", dname='" + dname + '\'' +
'}';
}
}
public class testDemo1 {
public static void main(String[] args)
{
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
String sql="select * from dept";
List<Emp> list=template.query(sql, new RowMapper<Emp>() {
//该方法每调用一次,就会封装一个Emp对象然后返回
@Override
public Emp mapRow(ResultSet resultSet, int i) throws SQLException {
Emp emp=new Emp();
emp.did=resultSet.getInt("did");
emp.dname=resultSet.getString("dname");
return emp;
}
});
for(Emp emp:list)
System.out.println(emp);
}
}
简化----查询所有记录,使用BeanPropertyRowMapper对象
class Emp{
public Integer money;//基本类型不接受赋值为null,要注意
public String name;
public Integer getMoney() {
return money;
}
public String getName() {
return name;
}
public void setMoney(Integer money) {
this.money = money;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Emp{" +
"money=" + money +
", name='" + name + '\'' +
'}';
}
}
public class testDemo1 {
public static void main(String[] args)
{
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
String sql="select * from login";
//传入一个Emp的字节码文件对象,用反射去比较属性字段名和数据库字段名是否匹配,如果匹配就会把值拿出来装到对应set和get方法里面
List<Emp> list=template.query(sql,new BeanPropertyRowMapper<Emp>(Emp.class));
for(Emp emp:list)
{
System.out.println(emp);
}
}
}
注意:
传入一个Emp的字节码文件对象,用反射去比较属性字段名和数据库字段名是否匹配,如果匹配就会把值拿出来装到对应set和get方法里面
查询总记录数量:
public class testDemo1 {
public static void main(String[] args)
{
//创建JDBCTemplate对象-----------需要一个DataSource对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
//查询总数,这里最后传入主键,提供效率
String sql="select count(did) from dept";
//返回一个long类型的值
Long total=template.queryForObject(sql,long.class);
System.out.println(total);
}
}