JDBC的学习笔记
JDBC的概念:
- JDBC API 允许用户访问任何形式的表格数据,尤其是存储在关系数据库中的数据。
执行流程:
连接数据源,如:数据库。
为数据库传递查询和更新指令。
处理数据库响应并返回的结果。
JDBC 架构:
分为双层架构和三层架构。
- 双层
作用:此架构中,Java Applet 或应用直接访问数据源。
条件:要求 Driver 能与访问的数据库交互。
机制:用户命令传给数据库或其他数据源,随之结果被返回。
部署:数据源可以在另一台机器上,用户通过网络连接,称为 C/S配置(可以是内联网或互联网)。
- 三层
侧架构特殊之处在于,引入中间层服务。
流程:命令和结构都会经过该层。
吸引:可以增加企业数据的访问控制,以及多种类型的更新;另外,也可简化应用的部署,并在多数情况下有性能优势。
历史趋势:
以往,因性能问题,中间层都用 C 或 C++ 编写,随着优化编译器(将 Java 字节码 转为 高效的 特定机器码)和技术的发展,如EJB,Java 开始用于中间层的开发这也让 Java 的优势突显出现出来,使用 Java 作为服务器代码语言,JDBC随之被重视。
JDBC的连接:
方法一:获取drive来实现类对象。
- 语法:
public class jdbcxuexi {
@Test
public void test() throws SQLException {
Driver driver = new com.mysql.jdbc.Driver();
String url = "jdbc:mysql://localhost:3306/test";
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password","密码");
Connection conn =(Connection) driver.connect(url, info);
System.out.print(conn);
}
}
- jdbc:mysql:是协议。 localhost:是IP地址。 3306是端口号。
方法二:采用drive实现类对象,采用反射。具有可移植性。
@Test
public void test2() throws Exception {
Class Class = java.lang.Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) Class.newInstance();
String url = "jdbc:mysql://localhost:3306/test";
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password","密码");
Connection conn =(Connection) driver.connect(url, info);
System.out.print(conn);
方式三:
- 注册驱动,获取连接。
@Test
public void test3() throws Exception {
Class Class = java.lang.Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) Class.newInstance();
String url ="jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "密码";
//注册驱动
DriverManager.registerDriver(driver);
//获取连接
Connection coon = (Connection) DriverManager.getConnection(url, user, password);
System.out.print(coon);
}
方法四:
@Test
public void test3() throws Exception {
String url ="jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "密码";
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection coon = (Connection) DriverManager.getConnection(url, user, password);
System.out.print(coon);
}
方式五:
- 将需要的信息放到配置文件中,通过读取配置文件的方式来获取信息,获取链接。
- 在src下配置一个文件,将需要的文件信息放在file,后缀为**(.properties)**
- 内容有:
user=root
url=jdbc:mysql://localhost:3306/test
password=密码
driverClass=com.mysql.jdbc.Driver
@Test
public void test4() throws Exception {
//读取配置文件信息
String path = System.getProperty("user.dir")+ "\\src\\jdbc.properties";
//文件的路径一定要准确,默认定位到的当前用户目录("user.dir")(即工程根目录)
//根据"user.dir" + "你自己设置的目录" 得到完整的路径(即绝对路径)
FileInputStream is = new FileInputStream(path);
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String url = pros.getProperty("url");
String password = pros.getProperty("password");
String driverClass = pros.getProperty("driverClass");
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection coon = (Connection) DriverManager.getConnection(url, user, password);
System.out.print(coon);
}
- 好处:实现数据与代码的分离,实现了解耦。可移植性。如果需要修改信息,只需修改文件。
使用preparedStatement实现CRUD的操作
操作和访问数据库
增删改数据库:
方式一:
- 增加数据:
public class PrearedStatement {
//增删改
//向表中增加数据
@Test
public void TestInsert() {
Connection coon = null;
PreparedStatement pS= null;
try {
//读取配置文件信息
//获取连接
String path = System.getProperty("user.dir")+ "\\src\\jdbc.properties";
FileInputStream is = new FileInputStream(path);
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String url = pros.getProperty("url");
String password = pros.getProperty("password");
String driverClass = pros.getProperty("driverClass");
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
coon = (Connection) DriverManager.getConnection(url, user, password);
//4.预编译sql语句,返回Preparedstatement的实例
String sql = "insert into T_mysql(name,company,capacity,age) value(?,?,?,?)";//?占位符
pS = coon.prepareStatement(sql);
//5.填充占位符
pS.setString(1, "闪电侠");
pS.setString(2, "DC");
pS.setString(3, "闪电侠");
pS.setString(4, "23434");
/*日期格式写法:
* SimpleDateFormat staff = new SmipleDateFormat("yea-MM-add");
* java.util.Date date = staff.parse("需要解析的字符串,1000-21-21");
* pa.setDate(3,new Date(date.getTime()));
*/
//6.执行sql语句
pS.execute();//是一个查询结果,有返回结果时返回true ,增删改操作返回False
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//7.资源的关闭
try {
if(pS!=null)
pS.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(coon!=null)
coon.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
方式二:
- 第一先连接数据库,加载驱动,预编译SQL语句,关闭连接。修改的代码
package JDBCconnectionutil;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import com.mysql.jdbc.Connection;
public class Jdbcconnctionutils {
public static Connection Connectionutils() throws Exception{
String path = System.getProperty("user.dir")+ "\\src\\jdbc.properties";
FileInputStream is = new FileInputStream(path);
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String url = pros.getProperty("url");
String password = pros.getProperty("password");
String driverClass = pros.getProperty("driverClass");
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
Connection coon = (Connection) DriverManager.getConnection(url, user, password);
return coon;
}
public static void closeRescoure(Connection coon,PreparedStatement ps) {
try {
if(ps!=null)
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(coon!=null)
coon.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package xuexiStatementgai;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import JDBCconnectionutil.Jdbcconnctionutils;
public class xuexiStatementgai1 {
@Test
public void testUpdate() {
//获取连接
Connection con= null;
PreparedStatement ps=null;
try {
con = Jdbcconnctionutils.Connectionutils();
//sql语句
String sql=" update T_mysql set name = ?,capacity = ?where id = ?";
ps = con.prepareStatement(sql);
//填充占位符
ps.setString(1, "雷神");
ps.setString(2, "雷神");
ps.setString(3, "10");
//执行
ps.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JDBCconnectionutil.Jdbcconnctionutils.closeRescoure((com.mysql.jdbc.Connection) con, ps);
}
}
方式三:
此代码是通用增删改的代码,还要结合前面的代码来操作,只能操作在同一数据库的数据
//此代码是通用增删改的代码,还要结合前面的代码来操作,只能操作在同一数据库的数据
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
public class finalzengshangai {
@Test
public void Test() {
String sql = "update T_mysql set name = ?,capacity = ?where id = ?";
finalzengshangai(sql,"雷神","雷神","10");
}
public void finalzengshangai(String sql,Object ...args) {//占位符个数与可变行参个数一致
PreparedStatement ps = null;
Connection conn= null ;
//获取连接
try {
conn = Jdbcconnctionutils.Connectionutils();
//预编译sql语句,返回PrepareStatement实例对象
PreparedStatement pr = conn.prepareStatement(sql);
//填充占位符
for(int i=0;i<args.length;i++ ) {
pr.setObject(i+1, args[i]);//小心开头是以1开始,第二个是数组的参数
}
//执行
pr.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
}
查询信息:
方式一:
/**
*
* @author §星§.Y.
*/
package JDBCfinding;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Set;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate;
public class jdbcfind {
@Test
public void JDBCfind() {
Connection conn = null;
PreparedStatement ps = null;
//执行,并返回结果集
ResultSet result=null;
try {
conn = Jdbcconnctionutils.Connectionutils();
String sql= "select id,name,capacity,age,company from T_mysql where id = ?";
ps = conn.prepareStatement(sql);
ps.setObject(1, 10);
result = ps.executeQuery();
//处理结果集
if(result.next()) {//next()判断结果集下一条是否有数据,如果有数据返回true则指针下移,没有数据则返回False,指针不会下移。
//获取当前这条数据的各个字段值
int id = result.getInt(1);
String name = result.getString(2);
String capacity = result.getString(3);
int age = result.getInt(4);
String company = result.getString(5);
//方式一
//System.out.print("id"+id+"name"+name+"company"+company+"capacity"+capacity);
//方式二
//Object[] data = new Object[] {
// id,name,capacity,company,age
//};
//方式三:将数据封装为对象
JDBcdate data1 = new JDBcdate(age, name, company, capacity, id);
System.out.print(data1);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
Jdbcconnctionutils.closeRescoure(conn, ps, result);
}
}
}
/**
*
* @author §星§.Y.
*/
package JDBcfind.bean;
/*ORM编程思想(OBject relation mapping)
* 一数据表对应java类
* 表中的一个记录对应Java类的一个对象
* 表中的一个字段对应java的一个属性
*/
public class JDBcdate {
private int id;
private String name;
private String capacity;
private String company;
private int age;
public JDBcdate(int id, String name, String capacity, String company, int age) {
super();
this.id = id;
this.name = name;
this.capacity = capacity;
this.company = company;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCapacity() {
return capacity;
}
public void setCapacity(String capacity) {
this.capacity = capacity;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "JDBcdate [id=" + id + ", name=" + name + ", capacity=" + capacity + ", company=" + company + ", age="
+ age + "]";
}
}
针对一个表的通用查询:
/**
*
* @author §星§.Y.
*/
im
package JDBCchaxu;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate1;
public class JDBCChaxu {
@Test
public void testQuery() {
String sql ="select id,name,capacity,company from T_mysql where id = ?";
JDBcdate1 jdbccHaxu = JDBCCHaxu(sql, 10);
System.out.print(jdbccHaxu);
System.out.print("\n");
sql = "select id,name from T_mysql where id = ?";
jdbccHaxu = JDBCCHaxu(sql, 2);
System.out.print(jdbccHaxu);
}
public JDBcdate1 JDBCCHaxu(String sql,Object ...args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
if(rs.next()) {
JDBcdate1 jdbc = new JDBcdate1();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//需要获取列名的别名getColumuLable的情况
//表的字段名与类的属性名不一致,在声明sql语句时,使用类的属性名来命名字段的别名
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = JDBcdate1.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(jdbc, columnvalue);
}
return jdbc;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(conn, ps, rs);
}
return null;
}
}
针对不同的表的通用查询:
/**
*
* @author §星§.Y.
*/
im
package NewJDBCFinalFind;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate1;
public class NewJDBCFinalFinding {
@Test
public void testGetInstance() {
String sql = "select id,name,capacity,company from T_mysql where id = ?";
JDBcdate1 instance = getInstance(JDBcdate1.class, sql, 10);
System.out.print(instance);
}
//造的类用class来代替,也是反射。
public <T> T getInstance(Class<T> clazz,String sql,Object...args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
if(rs.next()) {
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnvalue);
}
return t;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(conn, ps, rs);
}
return null;
}
}
package JDBcfind.bean;
/**
*
* @author §星§.Y.
*/
/*ORM编程思想(OBject relation mapping)
* 一数据表对应java类
* 表中的一个记录对应Java类的一个对象
* 表中的一个字段对应java的一个属性
*/
public class JDBcdate1 {
private int id;
private String name;
private String capacity;
private String company;
private int age;
public JDBcdate1() {
super();
this.id = id;
this.name = name;
this.capacity = capacity;
this.company = company;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCapacity() {
return capacity;
}
public void setCapacity(String capacity) {
this.capacity = capacity;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "JDBcdate [id=" + id + ", name=" + name + ", capacity=" + capacity + ", company=" + company + ", age="
+ age + "]";
}
}
针对不同的表的通用多个数据查询:
package NewJDBCFinalFind;
/**
*
* @author §星§.Y.
*/
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate1;
public class NewJDBCFinalFinding {
@Test
public void testGetInstance() {
String sql = "select id,name,capacity,company from T_mysql where id < ?";
List<JDBcdate1> list = getInstance(JDBcdate1.class, sql, 9);
list.forEach(System.out::println);
}
//造的类用class来代替,也是反射。用list保持多条数据
public <T> List<T> getInstance(Class<T> clazz,String sql,Object...args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
//创建集合对象,保存每条数据
ArrayList<T> list = new ArrayList<T>();
while(rs.next()) {
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnvalue);
}
//将每一条数据放到list中
list.add(t);
}
return list;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(conn, ps, rs);
}
return null;
}
}
PrepareStatement好处:
- 解决sql注入问题,解决statement的拼串
- PrepareStatement可以操作Blob类型的数据,statement做不到。
- PrepareStatement可以实现更高效的批量操作。
操作BLOB类型字段:
类型:
-
知识点:
LOB介绍 :BLOB (binary large object),二进制大对象,是一个可以存储 二进制文件的容器。在计算机中,BLOB常常是数据库中用来存储二进制文件 的字段类型。BLOB是一个大文件,典型的BLOB是一张图片或一个声音文件, 由于它们的尺寸,必须使用特殊的方式来处理 (例如:上传、下载或者存放到一个数据库)。 根据Eric Raymond的 说法,处理BLOB的主要思想就是 让文件处理器(如数据库管理器)不去理会文件是什么, 而是关心如何去处理它。但也有专家强调,这种处理大数据对象的方法是 把双刃剑,它有可能引发一些问题,如存储的二进制文件过大,会使数据库的 性能下降。在数据库中存放体积较大的多媒体对象就是 应用程序处理BLOB的典型例子。
在数据库操作BLOB类型:
插入BLOB数据(增删改差不多):
package BLOBXueXi;
/**
*
* @author §星§.Y.
*下午12:50:15
* 2020年8月21日
*/
import java.io.File;
import java.io.FileInputStream;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
public class BLOBXUExi {
@Test
public void BLOBXUExi() throws Exception {
Connection conn = Jdbcconnctionutils.Connectionutils();
String sql = "insert into T_mysql(name,capacity,company,age,photo) value(?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, "闪电侠");
ps.setObject(2, "闪电侠");
ps.setObject(3,"闪电侠");
ps.setObject(4, 234);
FileInputStream in = new FileInputStream(new File("untitled0.png"));
ps.setBlob(5, in);
ps.execute();
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
查询操作:
方法一:
/**
*
* @author §星§.Y.
*/
package BLOBXueXi;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate1;
public class chaxu {
@Test
public void chaxu1() throws Exception {
Connection conn = JDBCconnectionutil.Jdbcconnctionutils.Connectionutils();
String sql ="select * from T_mysql where id = ?";
PreparedStatement ps = conn.prepareStatement(sql );
ps.setObject(1,10);
ResultSet rs = ps.executeQuery();
if(rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String capacity = rs.getString("capacity");
String company = rs.getString("company");
int age = rs.getInt("age");
JDBcdate1 data = new JDBcdate1();
System.out.print(data);
//将BLOB数据以文件形式保持下来,
Blob photo = rs.getBlob("photo");
InputStream is1= photo.getBinaryStream();
FileOutputStream fos = new FileOutputStream("java.png");
byte[] buffer = new byte[1024];
int len ;
while((len = is1.read(buffer))!= -1) {
fos.write(buffer, 0, len);
System.out.print(len);
}
fos.close();
is1.close();
}
Jdbcconnctionutils.closeRescoure(conn, ps, rs);
}
}
错误:
文件显示不出来:可能是文件的后缀不对.
批量插入数据:
方式一:
/**
*
* @author §星§.Y.
*/
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
public class 批量插入 {
@Test
public void cr() {
PreparedStatement ps= null;
Connection conn=null;
try {
long start = System.currentTimeMillis();
conn= Jdbcconnctionutils.Connectionutils();
String sql = "insert into goods(name)value(?)";
ps = conn.prepareStatement(sql);
for(int i = 1; i<=20000;i++) {
ps.setObject(1, "name_"+i);
ps.execute();
}
long end = System.currentTimeMillis();
System.out.print(end-start);//我的是25012
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
}
方式二:
package 批量插入;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
/**
*
* @author §星§.Y.
*下午1:42:32
* 2020年8月26日
*/
public class 批量插入二 {
@Test
public void 批量插入二() {
/*
* 1.addBatch、xecuteBatch、 clearBatch
* 2.mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持,
* ?rewriteBatchedStatement= true 写在配置文件的URL后面
*/
PreparedStatement ps= null;
Connection conn=null;
try {
long start = System.currentTimeMillis();
conn= Jdbcconnctionutils.Connectionutils();
String sql = "insert into goods(name)value(?)";
ps = conn.prepareStatement(sql);
for(int i = 1; i<=20000;i++) {
ps.setObject(1, "name_"+i);
//1.攒sql
ps.addBatch();
if(i%500 == 0) {
//2.执行batch
ps.executeBatch();
//清空batch
ps.clearBatch();
}
}
long end = System.currentTimeMillis();24163
System.out.print(end-start);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
}
方式三:
package 批量插入;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
/**
*
* @author §星§.Y.
*下午5:31:31
* 2020年8月26日
*/
public class 批量插入三 {
@Test
public void 批量插入三() {
/*
* 1.addBatch、xecuteBatch、 clearBatch
* 2.mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持,
* ?rewriteBatchedStatement= true 写在配置文件的URL后面
*/
PreparedStatement ps= null;
Connection conn=null;
try {
long start = System.currentTimeMillis();
conn= Jdbcconnctionutils.Connectionutils();
//设置不允许自动提交数
conn.setAutoCommit(false);
String sql = "insert into goods(name)value(?)";
ps = conn.prepareStatement(sql);
for(int i = 1; i<=20000;i++) {
ps.setObject(1, "name_"+i);
//1.攒sql
ps.addBatch();
if(i%500 == 0) {
//2.执行batch
ps.executeBatch();
//清空batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.print(end-start);2789
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
}
PreparedStatement vs Statement
- 代码的可读性和可维护性。
- PreparedStatement能最大可能提高性能:
- DBServer会对**预编译语句**提供性能优化。因为预编译语句有
可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,
那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入
编译过的语句执行代码中就会得到执行。
- 在statement语句中,即使是相同操作但因为数据内容不一样.,所以整个语句
本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句
编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。
- (语法检查,语义检查,翻译成二进制命令,缓存)
- PreparedStatement可以防止SQL注入
- 能操作Blob数据
Statement操作数据表的弊端:
- 问题一∶存在拼串操作,繁琐
- 问题二: 存在SQL注入问题
Java数据类型和MySq数据类型对应表:
数据库类型 | JDBC类型 | JDBC索引 |
---|---|---|
int | java.lang.Integer | 4 |
varchar | java.lang.String | 12 |
char | java.lang.String | 1 |
nchar | java.lang.String | 1 |
nvarchar | java.lang.String | 12 |
text | java.lang.String | -1 |
ntext | java.lang.String | -1 |
tinyint | java.lang.Integer | -6 |
int | java.lang.Integer | 4 |
tinyint | java.lang.Integer | -6 |
smallint | java.lang.Integer | 5 |
bit | java.lang.Boolean | -7 |
bigint | java.lang.Long | -5 |
float | java.lang.Double | 6 |
decimal | java.math.BigDecimal | 3 |
money | java.math.BigDecimal | 3 |
smallmoney | java.math.BigDecimal | 3 |
numeric | java.math.BigDecimal | 2 |
real | java.lang.Float | 7 |
uniqueidentifier | java.lang.String | 1 |
smalldatetime | java.sql.Timestamp | 93 |
datetime | java.sql.Timestamp 93 | |
timestamp | byte[] | -2 |
binary | byte[] | -2 |
varbinary | byte[] | -3 |
image | byte[] | -4 |
sql_variant | java.lang.String | 12 |
数据事务:
介绍:
- 事务:—组逻辑操作单元,使数据从一种状态变换到另一种状态。
- 事务处理(事务操作)∶保证所有事务都作为一个工作单元来执行,即使出现了
-故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么
所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理
系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
- 为确保数据库中数据的一致性,数据舶操纵应当是离散的成组的逻辑单元︰
-当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败
,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。
- 数据一旦提交,就不能回滚。例如:DDL操作
[(DDL操作的说明)](https://baike.baidu.com/item/DDL/21997?fr=aladdin)、
DML操作
[(DML操作的说明)](https://baike.baidu.com/item/数据操纵语言?fromtitle=DML&fromid=10035808)
在默认情况下自动提交数据,可以用setAutoCommit(false)
设置为不能自动提交。还有就是默认关闭连接时会自动提交数据。
方法一:
package 事务学习;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
public class 事务学习一 {
@Test
public void shiwuxuexiyi(){
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
//取消数据自动提交
conn.setAutoCommit(false);
String sql = "update goods set money = money-100 where name = ?";
finalzengshangai(conn,sql,"ss");
System.out.println(1/0);
String sql1 = "update goods set money = money+100 where name = ?";
finalzengshangai(conn,sql1,"cc");
//提交数据
conn.commit();
System.out.println("\n"+"转账成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
//回滚数据
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally {
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
public void finalzengshangai(Connection conn,String sql,Object ...args) {//占位符个数与可变行参个数一致
PreparedStatement ps = null;
try {
//预编译sql语句,返回PrepareStatement实例对象
ps = conn.prepareStatement(sql);
//填充占位符
for(int i=0;i<args.length;i++ ) {
ps.setObject(i+1, args[i]);//小心开头是以1开始,第二个是数组的参数
}
//执行
ps.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
//不要关闭连接
Jdbcconnctionutils.closeRescoure(null, ps);
}
}
}
JDBC事务处理
-
数据一旦提交,就不可回滚。
-
数据什么时候意味着提交?
o 当一个连接对象被创建时,默认情况下是自动提交事务∶每次执行一个SQL语句时,如果执行成功就会向数据库自动提交,而不能回滚。o 关闭数据库连接,数据就会自动的提交。如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。即同一个事务的多个操作必须在同一个连接下。
-
JDBC程序中为了让多个SQL语句作为一个事务执行:
O调用Connection对象的setAutoCommit(false);以取消自动提交事务 O 在所有的SQL语句都成功执行后,调用commit();方法提交事务。 O 在出现异常时,调用rollback();方法回滚事务。 O 注: setAutoCommit(true) 。尤其是在使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状setAutoCommit(true)。尤其是在使用数据库连接池技术时,执行close()方法前,建议恢复自动提交状态。
事务的ACID属性:
- 原子性(Atomicity )
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性( Consistency )
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。 - 隔离性(lsolation) 注重
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 - 持久性(Durability )
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
数据库的并发问题:
5. ·对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,
如果没有采取必要的隔离机制,就会导致各种并发问题:
O 脏读:对于两个事务丁1.T2,T1读取了已经被T2更新
但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的。
O 不可重复读:对于两个事务T1,T2,T1读取了一个字段,
然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了。
O 幻读:对于两个事务T1,T2,T1从一个表中读取了一个字段,
然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表,
就会多出几行。
6. 数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,
使它们不会相互影响,避免各种并发问题。
7. 一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,
不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
事务隔离:
事务隔离级别 | 描述 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
读未提交(read-uncommitted) | 允许事务读取未被其他事物提交的变更。脏读,不可重复读和幻读的问题都会出现 | 是 | 是 | 是 |
读已提交数据(read-committed) | 只允许事务读取已经被其它事务提交的变更。可以避免脏读,但不可重复读和幻读问只允许事务读取已经被其它事务提交的变更.可以避免脏读,但不可重复读和幻读问题 | 否 | 是 | 是 |
可重复读(repeatable-read) | 确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间。禁止其他事物对这个字段进行更新。可以避免脏读和不可重复读,但幻读的问题仍然存在.。 | 否 | 否 | 是 |
串行化(serializable) | 确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入,更新和删除操作。所有并发问题都可以避免.但性能十分低下. | 否 | 否 | 否 |
设置MySQl的隔离级别:
package data1.bean;
/*ORM编程思想(OBject relation mapping)
* 一数据表对应java类
* 表中的一个记录对应Java类的一个对象
* 表中的一个字段对应java的一个属性
*/
/**
* @author §星§.Y. 下午12:37:49 2020年8月30日
*/
public class data1 {
private int id;
private String name;
private int money1;
//必须是无参构造器
public data1() {
super();
this.id = id;
this.name = name;
this.money1 = money1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney1() {
return money1;
}
public void setMoney1(int money1) {
this.money1 = money1;
}
@Override
public String toString() {
return "data1 [id=" + id + ", name=" + name + ", money1=" + money1 + "]";
}
}
package 隔离级别;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import data1.bean.data1;
/**
1.
2. @author §星§.Y.
*下午4:11:40
3. 2020年8月29日
4. @param <sql>
*/
public class 隔离级别一{
@Test
public void shiwuyi() throws Exception {
Connection conn = Jdbcconnctionutils.Connectionutils();
//获取当前连接的隔离级别
System.out.print("\n"+conn.getTransactionIsolation());
//设置数据库的隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
System.out.print("\n"+conn.getTransactionIsolation());
//取消自动提交
conn.setAutoCommit(false);
String sql= "select name,money1,id from goods where id = ?";
data1 ser1 = getInstance(conn,data1.class,sql,4);
System.out.print("\n"+ser1);
}
@Test
public void 隔离事务一更新() throws Exception {
Connection conn = Jdbcconnctionutils.Connectionutils();
conn.setAutoCommit(false);
String sql="update goods set money1 = ? where id = ?";
finalzengshangai(conn,sql, 4000,"ss");
Thread.sleep(15000);
System.out.println("\n"+"完成");
}
public <T> T getInstance(Connection conn,Class<T> clazz,String sql,Object...args) {
PreparedStatement ps=null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
if(rs.next()) {
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = data1.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnvalue);
}
return t;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(null, ps, rs);
}
return null;
}
public static void finalzengshangai(Connection conn,String sql,Object ...args) {//占位符个数与可变行参个数一致
PreparedStatement ps = null;
//获取连接
try {
//预编译sql语句,返回PrepareStatement实例对象
PreparedStatement pr = conn.prepareStatement(sql);
//填充占位符
for(int i=0;i<args.length;i++ ) {
pr.setObject(i+1, args[i]);//小心开头是以1开始,第二个是数组的参数
}
//执行
pr.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
Jdbcconnctionutils.closeRescoure(conn, ps);
}
}
}
DAO及其分类:
package com.atguigu2.dao;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import JDBcfind.bean.JDBcdate1;
/**
*
* @author §星§.Y.
*下午4:49:57
* 2020年8月30日
*/
/*
* 封装了针对数据表的通用的操作
*/
public abstract class BaseDAO {
@Test
//查询一条数据
public <T> T getInstance(java.sql.Connection conn,Class<T> clazz,String sql,Object... args) {
PreparedStatement ps=null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
if(rs.next()) {
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnvalue);
}
return t;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(conn, ps, rs);
}
return null;
}
//查询多条数据
public <T> List<T> getInstanceforlist(java.sql.Connection conn,Class<T> clazz,String sql,Object... args) {
PreparedStatement ps=null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for(int i = 0;i<args.length;i++) {
ps.setObject(i+1, args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData data = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int count = data.getColumnCount();
//创建集合对象,保存每条数据
ArrayList<T> list = new ArrayList<T>();
while(rs.next()) {
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列
for(int i = 0;i<count;i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);
//获取每个列的列名
String columnName = data.getColumnName(i+1);
//给jdbc对象指定的columnName属性,赋值为columnValue;通过反射
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true);
field.set(t, columnvalue);
}
list.add(t);
}
return list;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//关闭
Jdbcconnctionutils.closeRescoure(null, ps, rs);
}
return null;
}
//更新数据
public int Update(java.sql.Connection conn,String sql,Object... args) {//占位符个数与可变行参个数一致
PreparedStatement ps = null;
try {
//预编译sql语句,返回PrepareStatement实例对象
ps = conn.prepareStatement(sql);
//填充占位符
for(int i=0;i<args.length;i++ ) {
ps.setObject(i+1, args[i]);//小心开头是以1开始,第二个是数组的参数
}
//执行
ps.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
//不要关闭连接
Jdbcconnctionutils.closeRescoure(null, ps);
}
return 0;
}
//<E>泛型用于查询特殊值的的通用方法
public <E> E getvalue(java.sql.Connection conn ,String sql ,Object... args) {
PreparedStatement ps= null;
ResultSet rs= null;
try {
ps = conn.prepareStatement(sql);
for(int i = 1;i<=args.length;i++) {
ps.setObject(i, args[i-1]);
}
rs = ps.executeQuery();
if(rs.next()) {
return (E)rs.getObject(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(null, ps, rs);
}
return null;
}
}
package com.atguigu2.dao;
import java.sql.Connection;
import java.util.List;
import data1.bean.data1;
//此表提供的一些功能
/**
*
* @author §星§.Y.
*下午10:22:11
* 2020年8月30日
*/
//用于规范针对于goods表的常用操作
public interface goodsDAO {
//goods(命名为data1)对象添加到数库中
void inesert (Connection conn ,data1 data1 );
//根据Id删除相应的记录
void deleteId(Connection conn ,int id);
//针对内存中的goods对象,去修改数据表中的记录
void update(Connection conn ,data1 data1);
// 根据Id来查询得到goods对象
data1 getgoodsById(Connection conn ,int id);
//查询表中的所有的记录构成的集合
List<data1> getAll(Connection conn);
//返回数据表中的条目数
Long getGoods(Connection conn );
//返回最多的钱
int getMaxmoney(Connection conn );
}
package com.atguigu2.dao;
import java.sql.Connection;
import java.util.List;
import JDBCconnectionutil.Jdbcconnctionutils;
import data1.bean.data1;
public class goodsDAOImpl extends BaseDAO implements goodsDAO{
@Override
public void inesert(Connection conn, data1 data1) {
// TODO Auto-generated method stub
String sql="insert into goods(name,money1) value(?,?)";
Update(conn,sql,data1.getName(),data1.getMoney1());
}
@Override
public void deleteId(Connection conn, int id) {
// TODO Auto-generated method stub
String sql="delete from goods where id= ?";
Update(conn,sql,id);
}
@Override
public void update(Connection conn,data1 data1) {
// TODO Auto-generated method stub
String sql="update goods set name= ?,money1 = ? where id=? ";
Update(conn,sql,data1.getName(),data1.getMoney1(),data1.getId());
}
@Override
public data1 getgoodsById(Connection conn, int id) {
// TODO Auto-generated method stub
String sql="select id ,name,money1 where id = ?" ;
data1 data1 = getInstance(conn, data1.class, sql, id);
return data1;
}
@Override
public List<data1> getAll(Connection conn) {
// TODO Auto-generated method stub
String sql= "select id,name,money1 from goods";
List<data1> list = getInstanceforlist(conn,data1.class,sql);
return list;
}
@Override
public Long getGoods(Connection conn) {
// TODO Auto-generated method stub
String sql ="select count(*) from goods";
return getvalue(conn ,sql);
}
@Override
public int getMaxmoney(Connection conn) {
// TODO Auto-generated method stub
String sql = "select max(money1) from goods";
return getvalue(conn ,sql);
}
}
package com.atguigu2.dao.junit;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import com.atguigu2.dao.goodsDAOImpl;
import com.mysql.jdbc.Connection;
import JDBCconnectionutil.Jdbcconnctionutils;
import data1.bean.data1;
/**
* 测试代码
* @author §星§.Y.建议单个代码进行测试
*下午9:03:38
* 2020年8月31日
*/
public class goodsDAOImplTEst {
goodsDAOImpl dao = new goodsDAOImpl();
@Test
public void testInesert() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
data1 data = new data1(1,"pp", 2000);
dao.inesert(conn, data);
System.out.print("转账成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testDeleteId() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
dao.deleteId(conn, 2);
System.out.print("删除成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testUpdate() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
data1 data = new data1(4,"dd",4000);
dao.update(conn, data);
System.out.print("更新成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testGetgoodsById() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
dao.getgoodsById(conn, 4);
System.out.print("获取成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testGetAll() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
List<data1> list = dao.getAll(conn);
list.forEach(System.out::println);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testGetGoods() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
dao.getGoods(conn);
System.out.print("部分成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
@Test
public void testGetMaxmoney() {
Connection conn = null;
try {
conn = Jdbcconnctionutils.Connectionutils();
dao.getMaxmoney(conn);
System.out.print("最大值成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Jdbcconnctionutils.closeRescoure(conn, null);
}
}
}
数据库连接池:
JDBC数据库连接池的必要性:
-
在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤︰
1. 在主程序(如servlet、beans )中建立数据库连接 2. 进行sql操作 3. 断开数据库连接
-
·这种模式开发,存在的问题:
1. 普通的JDBC数据库连接使用DriverManager来获取,每次向数据库建立 连接的时候都要将Connection加载到内存中,再验证用户名 和密码(得花费0.05s~1s的时间)。需要数据库连接的时候,就向数据库要求 一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。 数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至 几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的 甚至会造成服务器的崩溃。 3. 对于每一次数据库连接,使用完后都得断开。 否则,如果程序出现异常而未能关闭, 将会导致数据库系统中的内存泄漏,最终将导致重启数据库。 (回忆:何为Java的内存泄漏?) 4. 这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配 出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
数据库连接池技术:
3. 为解决传统开发中的数据库连接问题,可以采用数据库连接池技术。
4. 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些
数据库连接的数量是由最小数据库要建立数据库连接时,只需从“缓冲池"中取出
一个,使用完毕之后再放回去。
5. 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用
一个现有的数据库连接,而不是重新建立一个。
6. 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些
数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否
被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库
连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的
连接数超过最大连接数量时,这些请求将被加入到等待队列中。
多种开源的数据库连接池:
3. JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只
是一个接口,该接口通常由服务器(Weblogic,WebSphere,Tomcat)提供实现,
也有一些开源组织提供实现∶
1. DBCP是Apache提供的数据库连接池。tomcat服务器自带
dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,
Hibernate3已不再提供支持。
2. C3P0是一个开源组织提供的一个数据库连接池,速度相对较慢,
稳定性还可以。hibernate官方推荐使用。
3.Proxool是sourceforge下的一个开源项目数据库连接池,有监控
连接池状态的功能,稳定性较c3p0差一点。
4.BoneCP是一个开源组织提供的数据库连接池,速度快
5. Druid是阿里提供的数据库连接池,据说是集DBCP、C3PO、
Proxool优点于一身的数据库连接池,但是速度不确定是否有BoneCP快。
4. DataSource通常被称为数据源,它包含连接池和连接池管理两个部分,
习惯上也经常把DataSource称为连接池
5.DataSource用来取代DriverManager来获取Connection,获取速度快,
同时可以大幅度提高数据库访问速度。
C3P0的连接:
注意:
1. 导jar包:jar:c3P0-0.9.1.2和mchange-commons-java-0.2.3.4
2. 如果报错,可能没有导到mchange-commons-0.2.jar这个包。
3.自己的错误:
!配置文件注意:
文件没找到:
一、c3p0配置文件名字一定是c3p0-config.xml;
二、c3p0-config.xml放在src下面 和java package 一个层次;
连接:
1.连接代码:
package com.atguigu3.connection;
import org.junit.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import java.sql.Connection;
import java.sql.SQLException;
/**
* jar:c3P0-0.9.1.2和mchange-commons-java-0.2.3.4
* @author §星§.Y.
*下午2:54:58
* 2020年9月1日
*/
public class C3P0test {
@Test
//方式一:
public void C3P0Test() throws Exception{
//获取c3p0数据库连接池
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "com.mysql.jdbc.Driver" );
cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/data" );
cpds.setUser("root");
cpds.setPassword("密码");
//通过设置相关的参数来对数据库连接池进行管理:
//设置初始时数据库连接池的连接数
cpds.setInitialPoolSize(10);
Connection conn = cpds.getConnection();
System.out.print(conn);
//销毁C3p0数据库链接池,一般不会关
DataSources.destroy(cpds);
}
//方式二:使用配置文件
@Test
public void C3P0Test2() throws Exception {
ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");//使用xml中named-config的值
Connection conn = cpds.getConnection();
System.out.print(conn);
}
}
2.配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 自定义的配置文件,named-config的值可以改,//localhost:3306/可以省略,写成///-->
<named-config name="helloc3p0">
<!-- 提供获取链接的4个信息-->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/data</property>
<property name="user">root</property>
<property name="password">密码</property>
<!-- 进行数据库连接池管理的基本信息-->
<!--当数据库连接池的连接数不够时,c3p0一次性向数据库服务器申请的连接数5-->
<property name="acquireIncrement">5</property>
<!-- c3p0数据库连接池中初始化的连接数10-->
<property name="initialPoolSize">10</property>
<!-- 数据库连接池维护的最少连接数10-->
<property name="minPoolSize">10</property>
<!-- 数据库连接池维护的最多连接数100-->
<property name="maxPoolSize">100</property>
<!-- 数据库连接池维护的最多Statement的个数50-->
<property name="maxStatements">50</property>
<!-- 每个连接中可以最多使用的Statemnet的个数2-->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
测试方式二:
- 测试代码:
package com.atguigu4.connection.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.atguigu2.dao.goodsDAOImpl;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import data1.bean.data1;
public class JDBcutils {
@Test
public void testUpdate() {
goodsDAOImpl dao = new goodsDAOImpl();
Connection conn = null;
try {
conn = getConnection1();
data1 data1 = new data1(4,"bb",6000 );
dao.update(conn, data1);
System.out.print("更新成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
closeRescoure(conn, null);
}
}
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
/*
使用xml中named-config的值
造一个连接池就好
*/
public static Connection getConnection1() throws Exception {
Connection conn = cpds.getConnection();
return conn;
}
public static void closeRescoure(Connection coon,PreparedStatement ps) {
try {
if(ps!=null)
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(coon!=null)
coon.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package com.atguigu2.dao;
import java.sql.Connection;
import java.util.List;
import JDBCconnectionutil.Jdbcconnctionutils;
import data1.bean.data1;
public class goodsDAOImpl extends BaseDAO implements goodsDAO{
@Override
public void inesert(Connection conn, data1 data1) {
// TODO Auto-generated method stub
String sql="insert into goods(name,money1) value(?,?)";
Update(conn,sql,data1.getName(),data1.getMoney1());
}
@Override
public void deleteId(Connection conn, int id) {
// TODO Auto-generated method stub
String sql="delete from goods where id= ?";
Update(conn,sql,id);
}
@Override
public void update(Connection conn,data1 data1) {
// TODO Auto-generated method stub
String sql="update goods set name= ?,money1 = ? where id=? ";
Update(conn,sql,data1.getName(),data1.getMoney1(),data1.getId());
}
@Override
public data1 getgoodsById(Connection conn, int id) {
// TODO Auto-generated method stub
String sql="select id ,name,money1 where id = ?" ;
data1 data1 = getInstance(conn, data1.class, sql, id);
return data1;
}
@Override
public List<data1> getAll(Connection conn) {
// TODO Auto-generated method stub
String sql= "select id,name,money1 from goods";
List<data1> list = getInstanceforlist(conn,data1.class,sql);
return list;
}
@Override
public Long getGoods(Connection conn) {
// TODO Auto-generated method stub
String sql ="select count(*) from goods";
return getvalue(conn ,sql);
}
@Override
public int getMaxmoney(Connection conn) {
// TODO Auto-generated method stub
String sql = "select max(money1) from goods";
return getvalue(conn ,sql);
}
}
- data1的代码:
package data1.bean;
/*ORM编程思想(OBject relation mapping)
* 一数据表对应java类
* 表中的一个记录对应Java类的一个对象
* 表中的一个字段对应java的一个属性
*/
/**
* @author §星§.Y. 下午12:37:49 2020年8月30日
*/
public class data1 {
private int id;
private String name;
private int money1;
//必须是无参构造器
public data1() {
super();
this.id = id;
this.name = name;
this.money1 = money1;
}
/**
* @param id
* @param name
* @param money1*/
public data1(int id, String name, int money1) {
super();
this.id = id;
this.name = name;
this.money1 = money1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney1() {
return money1;
}
public void setMoney1(int money1) {
this.money1 = money1;
}
@Override
public String toString() {
return "data1 [id=" + id + ", name=" + name + ", money1=" + money1 + "]";
}
}
DBCP连接:
配置文件:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///data
username=root
password=密码
initialSize=10
连接:
package com.atguigu3.connection;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
/**
* 测试DBCP的连接池技术
* @author §星§.Y.
*下午3:20:29
* 2020年9月2日
*/
public class DBCPtest {
@Test
//方式一:
public void dbcdtest() throws Exception {
BasicDataSource Source = new BasicDataSource();
//设置基本信息
Source.setDriverClassName("com.mysql.jdbc.Driver");
Source.setUrl("jdbc:mysql:///data");
Source.setUsername("root");
Source.setPassword("密码");
//设置其他涉及 数据库连接池的相关管理属性:
Source.setInitialSize(10);
Source.setMaxActive(10);
Connection conn = Source.getConnection();
System.out.print(conn);
}
//方式二:使用配置文件
@Test
public void dbcdtest1() throws Exception{
Properties pros = new Properties();
//方式一
//InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
//方式二:
FileInputStream is= new FileInputStream(new File("src/dbcp.properties"));
pros.load(is);
DataSource source = BasicDataSourceFactory.createDataSource(pros);
Connection conn = source.getConnection();
System.out.print(conn);
}
}
测试:
package com.atguigu4.connection.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
/**
*
*
* @author §星§.Y.
*上午10:38:27
* 2020年9月3日
*/
public class DBCPconnectionutils {
private static DataSource source;
static{//执行一次就好
Properties pros = new Properties();
//方式一
//InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
//方式二:
try {
FileInputStream is= new FileInputStream(new File("src/dbcp.properties"));
pros.load(is);
//创建连接池
source= BasicDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection TestConnection() throws Exception {
Connection conn = source.getConnection();
return conn;
}
}
package com.atguigu4.connection.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.atguigu2.dao.goodsDAOImpl;
import data1.bean.data1;
public class JDBcutils {
@Test
public void testUpdate() {
goodsDAOImpl dao = new goodsDAOImpl();
Connection conn = null;
try {
conn =DBCPconnectionutils.TestConnection();
data1 data1 = new data1(4,"ooo",9000 );
dao.update(conn, data1);
System.out.print("更新成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
closeRescoure(conn, null);
}
}
public static void closeRescoure(Connection coon,PreparedStatement ps) {
try {
if(ps!=null)
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(coon!=null)
coon.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Druid(德鲁)连接(常用的):
配置文件:
url=jdbc:mysql:///data
username=root
password=密码
driverClassname=com.mysql.jdbc.Driver
initialSize=10
maxActive=10
package com.atguigu4.connection.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.junit.Test;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
public class DruidTest {
@Test
public void Druidtext() throws Exception {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("durid.properties");
pros.load(is);
DataSource dataSource = DruidDataSourceFactory.createDataSource(pros);
Connection conn = dataSource.getConnection();
System.out.print(conn);
}
}
- 优化:
package com.atguigu4.connection.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/**
1.
2. @author §星§.Y.
*下午3:34:31
3. 2020年9月3日
*/
public class Duridconnectionutils {
private static DataSource source;
static{//执行一次就好
try {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("durid.properties");
pros.load(is);
source = DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection TestConnection1() throws Exception {
Connection conn = source.getConnection();
return conn;
}
}
Apache—DbUtils组件的使用:
原理:
1. commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,
它是对JDBC的简单封装,并且使用dbutils能极大简化jdbc编码的工作量,
同时也不会影响程序的性能!
插入测试:
package com.atguigu4.connection.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/**
*
*
* @author §星§.Y.
*上午10:38:27
* 2020年9月3日
*/
public class Duridconnectionutils1 {
private static DataSource source;
static{//执行一次就好
try {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("durid.properties");
pros.load(is);
source = DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection TestConnection() throws Exception {
Connection conn = source.getConnection();
return conn;
}
}
package com.atguigu5.connection.util;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import com.atguigu4.connection.util.Duridconnectionutils1;
/**
*
* @author §星§.Y.
*下午4:24:05
* 2020年9月3日
*/
public class qurrytest {
@Test
public void qurrytest1() throws Exception {
QueryRunner query = new QueryRunner();
Connection conn = Duridconnectionutils1.TestConnection();
String sql ="insert into goods(name,money1) values(?,?) ";
int update = query.update(conn, sql, "ff",19003);
System.out.print(update);
}
}