// *** 填入自己的相关信息
Driver driver = new com.mysql.jdbc.Driver();
Properties properties=new Properties();
String url="jdbc:mysql://localhost:3306/***?useSSL=false";
properties.setProperty("user","***");
properties.setProperty("password","***");
Connection connect = driver.connect(url, properties);
connect.close();
基本介绍
// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';
// 用户输入用户名:1'or' 输入密码:='1'or'1'='1'
// 最终导致条件变为: USER='1' or 'AND PASSWORD='='1' or '1'='1' 最终条件始终为真
String sql = "SELECT user,password FROM user_table WHERE user = '" + userName + "' AND password = '" + password
+ "'";
基本介绍
好处:
//1.读取配置文件中的4个基本信息
InputStream is=ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties info=new Properties();
info.load(is);
String url=info.getProperty("url");
String user=info.getProperty("user");
String password=info.getProperty("password");
String driverClass=info.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取连接
Connection conn= DriverManager.getConnection(url,user,password);
//4.预编译sql语句,返回PreparedStatement的实例
// 添加功能
String sql="insert into customers(name,email,birth) value(?,?,?)";
PreparedStatement ps= conn.prepareStatement(sql);
//5.填充占位符
ps.setString(1,"哪吒");
ps.setString(2,"[email protected]");
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date=sdf.parse("1000-01-01");
ps.setDate(3,new Date(date.getTime()));
//6.执行操作
ps.execute();
//修改功能
String sql1="update customers set birth=? where name=?";
PreparedStatement ps1= conn.prepareStatement(sql1);
//5.填充占位符
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date=sdf.parse("2022-01-01");
ps1.setDate(1,new Date(date.getTime()));
ps1.setString(2,"哪吒");
//6.执行操作
ps1.execute();
//删除功能
String sql2="delete from customers where name=?";
PreparedStatement ps2= conn.prepareStatement(sql2);
//5.填充占位符
ps2.setString(1,"哪吒");
//6.执行操作
ps2.execute();
//查找功能
String sql3="select * from customers where id=?";
PreparedStatement ps3= conn.prepareStatement(sql3);
//5.填充占位符
ps3.setInt(1,1);
//6.执行并返回结果集
ResultSet rs=ps3.executeQuery();
ArrayList<Customers> list=new ArrayList<>();
//处理结果集
while (rs.next()){//next()判断是否还有下一条数据
int id=rs.getInt(1);
String name=rs.getString(2);
String email=rs.getString(3);
Date birth=rs.getDate(4);
Customers customer=new Customers(id,name,email, birth);
list.add(customer);
}
for (Customers c:list
) {
System.out.println(c);
}
//7.关闭资源(实际应该是需要处理异常)
conn.close();
is.close();
ps.close();
ps1.close();
ps2.close();
ps3.close();
// 集中实现批量添加的方法的效率比较
//方式一:比较慢
@Test
//批量添加
public void insertAll() throws Exception {
Connection conn=getConnection();
String sql="insert into goods(name) values(?)";
PreparedStatement ps=conn.prepareStatement(sql);
long start=System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
ps.setObject(1,"name_"+i);
ps.execute();
}
long end=System.currentTimeMillis();
System.out.println(end-start);
ps.close();
conn.close();
}
//方式二:较快,还有优化空间(110766ms)
//使用Batch,需要使用驱动MySQL5.1.37,并且在配置文件的url后面加 ?rewriteBatchedStatements=true
@Test
//批量添加
public void insertBatchAll() throws Exception {
Connection conn=getConnection();
String sql="insert into goods(name) values(?)";
PreparedStatement ps=conn.prepareStatement(sql);
long start=System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
ps.setObject(1,"name_"+i);
//攒sql
ps.addBatch();
if (i%500==0){
//执行batch
ps.executeBatch();
//清sql,之前攒的SQL全部执行
ps.clearBatch();
}
}
long end=System.currentTimeMillis();
System.out.println(end-start);
ps.close();
conn.close();
}
//方式三:不允许自动提交(12682ms)
@Test
//批量添加
public void insertBatchAllNotCommit() throws Exception {
Connection conn=getConnection();
//不允许自动提交
conn.setAutoCommit(false);
String sql="insert into goods(name) values(?)";
PreparedStatement ps=conn.prepareStatement(sql);
long start=System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
ps.setObject(1,"name_"+i);
//攒sql
ps.addBatch();
if (i%500==0){
//执行batch
ps.executeBatch();
//清sql,之前攒的SQL全部执行
ps.clearBatch();
}
}
conn.commit();
long end=System.currentTimeMillis();
System.out.println(end-start);
ps.close();
conn.close();
}
Connection conn=null;
try {
conn=getConnection();
//关闭事务自动提交
conn.setAutoCommit(false);
String sql1="update user_table set balance=balance+100 where user=?";
update(conn,sql1,"AA");
//模拟异常
System.out.println(10/0);
String sql2="update user_table set balance=balance-100 where user=?";
update(conn,sql2,"BB");
//执行事务
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
//发生错误回滚事务
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//jdbc:mysql 协议
//localhost ip地址
//3306 默认的mysql的端口号
//*** 需要连接的数据库名
//方式一
//需要在路径中加入驱动
//获取Driver的实现类对象
Driver driver = new com.mysql.jdbc.Driver();
String url = "jdbc:mysql://localhost:3306/***";
//将用户名和密码封装到Properties
Properties info = new Properties();
info.setProperty("user", "***");
info.setProperty("password", "***");
//也可以直接 Connect(url,user,password),不适用Properties
Connection conn = driver.connect(url, info);
System.out.println(conn);
//方式二
//获取Driver的实现类对象,用反射实现
Class clazz=Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
String url = "jdbc:mysql://localhost:3306/***";
//将用户名和密码封装到Properties
Properties info = new Properties();
info.setProperty("user", "***");
info.setProperty("password", "***");
Connection conn = driver.connect(url, info);
System.out.println(conn);
方式三
//获取Driver的实现类对象,并使用DriverManager来注册
Class clazz=Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
String url = "jdbc:mysql://localhost:3306/***";
String user="***";
String password="***";
//注册驱动
DriverManager.registerDriver(driver);
//获取连接
Connection conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);
方式四
//获取Driver的实现类对象,省略注册驱动(在mysql 的Driver实现类中,自动注册了)
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/***";
String user="***";
String password="***";
//获取连接
Connection conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);
方式五(注意:配置文件要放在src下):最终版
优点:1.实现数据域代码分离,实现解耦
2.如果需要修改配置文件信息,可以避免重新打包
//通过配置文件来读取相关配置
InputStream is=当前类.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties info=new Properties();
info.load(is);
String user=info.getProperty("user");
String password=info.getProperty("password");
String url=info.getProperty("url");
String driverClass=info.getProperty("driverClass");
//获取Driver的实现类对象
Class.forName(driverClass);
Connection conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);
自己的DAO可以继承BaseDao
//JDBCUtils
public class JDBCUtils {
public static Connection getConnection() throws Exception {
//1.读取配置文件中的4个基本信息
InputStream is=ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties info=new Properties();
info.load(is);
String url=info.getProperty("url");
String user=info.getProperty("user");
String password=info.getProperty("password");
String driverClass=info.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取连接
Connection conn= DriverManager.getConnection(url,user,password);
return conn;
}
public static void closeResource(Connection conn, Statement ps){
try {
if(ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
try {
if(ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//BaseDAO
public abstract class BaseDAO<T> {
private Class<T> clazz = null;
{
//获取当前BaseDAO的子类继承的父类中的泛型
Type genericSuperclass = this.getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
Type[] typeArguments = paramType.getActualTypeArguments();//获取了父类的泛型参数
clazz = (Class<T>) typeArguments[0];//泛型的第一个参数
}
// 通用的增删改操作---version 2.0 (考虑上事务
public int update(Connection conn, String sql, Object... args) {// sql中占位符的个数与可变形参的长度相同!
PreparedStatement ps = null;
try {
// 1.预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
}
// 3.执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4.资源的关闭
JDBCUtils.closeResource(null, ps);
}
return 0;
}
// 通用的查询操作,用于返回数据表中的一条记录(version 2.0:考虑上事务
public T getInstance(Connection conn, 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
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
// 处理结果集一行数据中的每一个列
for (int i = 0; i < columnCount; i++) {
// 获取列值
Object columValue = rs.getObject(i + 1);
// 获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(null, ps, rs);
}
return null;
}
// 通用的查询操作,用于返回数据表中的多条记录构成的集合(version 2.0:考虑上事务
public List<T> getForList(Connection conn, 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
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
// 创建集合对象
ArrayList<T> list = new ArrayList<T>();
while (rs.next()) {
T t = clazz.newInstance();
// 处理结果集一行数据中的每一个列:给t对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
// 获取列值
Object columValue = rs.getObject(i + 1);
// 获取每个列的列名
// String columnName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(null, ps, rs);
}
return null;
}
//用于查询特殊值的通用的方法
public <E> E getValue(Connection conn,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();
if(rs.next()){
return (E) rs.getObject(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(null, ps, rs);
}
return null;
}
}
JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource只是一个接口,该接口通常由第三方提供实现[提供 .jar]
//配置文件c3p0-config.xml
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<named-config name="myC3P0">
<!-- 获取连接的4个基本配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?rewriteBatchedStatements=true</property>
<property name="user">root</property>
<property name="password">***</property>
<!-- 进行数据库连接池管理的基本信息-->
<!-- 连接池的连接不够时的增长步数 -->
<property name="acquireIncrement">5</property>
<!-- 初始化连接池的数量 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数-->
<property name="minPoolSize">5</property>
<!--最大连接数量-->
<property name="maxPoolSize">100</property>
<!-- 维护最多的Statements的个数-->
<property name="maxStatements">0</property>
<!--每个连接可使用的Statements数量-->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
ComboPooledDataSource cpds = new ComboPooledDataSource("myC3P0");
Connection conn=cpds.getConnection();
System.out.println(conn);
Connection conn1=cpds.getConnection();
System.out.println(conn1);
//配置文件dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?rewriteBatchedStatements=true
username=root
password=***
initialSize=10
maxActive=10
//创建DBCP的数据库连接池
InputStream is=ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
Properties pros=new Properties();
pros.load(is);
DataSource source=BasicDataSourceFactory.createDataSource(pros);
Connection conn1=source.getConnection();
System.out.println(conn1);
Connection conn2=source.getConnection();
System.out.println(conn2);
//配置文件与dbcp.properties一样
//需要先引入相关的包,然后再编写代码
//创建DBCP的数据库连接池
InputStream is=ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
Properties pros=new Properties();
pros.load(is);
DataSource source= DruidDataSourceFactory.createDataSource(pros);
Connection conn1=source.getConnection();
System.out.println(conn1);
Connection conn2=source.getConnection();
System.out.println(conn2);
使用:
QueryRunner runner=new QueryRunner();
Connection conn= JDBCUtils.getConnection();
//使用
runner.XXX(conn,sql,参数列表);