什么是JDBC
概念
JDBC(Java Datebase Connectivity),java连接数据库的规范(标准)使用JDBC连接完成连接数据库完成CRUD操作
核心思想
Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问的方式
由数据库厂商提供驱动实现类(Driver数据库驱动)
JDBC开发
开发步骤
DriverManager
//(1) 注册两次 (2)耦合性高
//DriverManager.registerDriver(new Driver());
Statement
概念:
获取连接对象后,可以创建Statement对象,用来执行命令
Statement stat = 连接对象.createStatement();
ResultSet
概念
在执行查询SQL后,存放查询到的结果集数据
接收结果集
ResultSet rs = statement executeQuery(sql);
注意
作用就是完成了查询结果的储存功能,而且只能读取一次,不能够来回的滚动读取
遍历ResultSet
常见的错误
SQL注入
原因
用户输入的数据中有SQL关键字或语法并且参与了SQL语句的编译,导致SQL语句编译后的条件含义为true,一直得到正确的结果,这种现象称为SQL注入
如何避免
由于编写SQL语句是在用户输入数据整合后再编译
我们要使SQL语句在用户输入数据前就已编译好完成的SQL语句,再进行填充数据
PreparedStatement
概念:
PreparedStatement继承了Statement接口,执行SQL语句的方法无异
作用
①预编译SQL语句,效率高
②安全,避免SQL注入
③可以动态的填充数据,执行多个同构的SQL语句
应用
关于时间的转换
//自动转
MySQL Date ----> java.sql.Date
MySQL Time ----> java.sql.Time
MySQL DateTime ----> java.sql.TimeStamp
MySQL TimeStamp ----> java.sql.TimeStamp
java.sql.Date、java.sql.Time、java.sql.TimeStamp有共同的父类 java.util.Date();
我们在获取或者设置时间时,如果不知道就设置为Object类型
举例
public class JDBCDemo5 {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
String url = "jdbc:mysql://localhost:3306/day25?useSSL=false&characterEncoding=utf-8";
Connection conn = DriverManager.getConnection(url, "root", "root");
//3.创建命令
//3.1添加
// PreparedStatement pstat = conn.prepareStatement("insert into student(name,age,sex,bornDate,phone,address)" +
// "values (?,?,?,?,?,?);");
// for (int i = 0; i < 10; i++) {
// pstat.setString(1, "赵三"+ i);
// pstat.setInt(2, 18);
// pstat.setString(3, "男");
// pstat.setObject(4, new Date());
// pstat.setString(5, "46337843");
// pstat.setString(6, "北京");
// //4.执行命令
// int count1 = pstat.executeUpdate();
// System.out.println("count1:"+count1);
// }
//3.2修改
// PreparedStatement pstat = conn.prepareStatement("update student set address = ?;");
// pstat.setString(1, "杭州");
//3.3删除
// PreparedStatement pstat = conn.prepareStatement("delete from student where id=?");
// pstat.setInt(1, 1);
//3.4查询
PreparedStatement pstat = conn.prepareStatement("select * from student");
ResultSet rs = pstat.executeQuery();
while (rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String sex = rs.getString("sex");
String bornDate = rs.getString("bornDate");
String address = rs.getString("address");
System.out.println(id+"\t"+name+"\t"+age+"\t"+sex+"\t"+bornDate+"\t"+address);
}
//5.关闭
pstat.close();
conn.close();
}
}
工具类
封装工具类
背景:重用性方案中的参数都是硬编码,当驱动、url等参数需要更换时,需要重新编译。通过配置文件读取配置信息,使用软编码方式,更灵活的方案
跨平台方案:
流:InputStream is = DbUtil.class.getClassLoader().getResourceAsStream(“db.properties”);
properties.load(is);
public class DbUtil {
private static String driver;
private static String url;
private static String user;
private static String password;
//1.注册驱动
static {
try {
Properties properties = new Properties();
InputStream is = DbUtil.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(is);
driver= properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//2.建立连接
public static Connection getConnection(){
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//3.释放资源
public static void closeAll(ResultSet rs, Statement stat,Connection conn){
try {
if (rs != null){
rs.close();
}
if (stat != null){
stat.close();
}
if (conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) throws SQLException {
//注册驱动
Connection conn = DbUtil.getConnection();
//.2建立连接
Statement stat = conn.createStatement();
//3.执行
ResultSet rs = stat.executeQuery("select * from student;");
//4.处理数据
while (rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String sex = rs.getString("sex");
Date bornDate = rs.getDate("bornDate");
String phone = rs.getString("phone");
String address = rs.getString("address");
System.out.println(id + "\t" + name + "\t" + age + "\t" + sex + "\t" + bornDate + "\t" + phone + "\t" + address );
}
//关闭
DbUtil.closeAll(rs, stat, conn);
}
}
ORM
概念:Object Relational Mapping:对象关系映射
对结果集(ResultSet)遍历时,取出的都是零散的数据
在实际开发应用中,我们需要将零散的数据进行封装整理
实体类:
DAO
概念:
Date Access Object:数据访问对象
DAO实现了业务逻辑与数据库访问相分离
对同一张表的所有的操作都封装在XxxDaoImpl对象中
根据增删改查提供的具体方法(insert、update、delete、select、selectAll)
Service
概念:代表用户完成的一个业务功能,可以由一个或多个DAO的调用组成,软件所提供的一个功能叫做业务;
举例:银行
事务
概念:
事务是一个原子操作,是一个最小的执行单元,由一个或多个SQL语句组成。
在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功
有一个SQL语句执行失败,整个事务都执行失败
事务的边界:
在jdbc中,先获得Connection对象
开始事务:conn.setAutoCommit(false);
手动提交事务:conn.commit();
手动回滚事务:conn.rollback();
在Service中,调用了多次DAO操作,每一个业务功能都要控制事务
ThreadLocal
ThreadLocal:
每一个线程通过ThreadLocal绑定一个连接对象
在整个流程中任一环节可以存值或取值
通过 ThreadLocal.get()方法来获取连接,通过ThreadLocal.remove来移除连接
三层架构
数据库连接池
连接池作用:
数据库连接池负责分配、管理和释放数据库连接
在程序初始化时,预先创建指定数量的数据库连接对象存储在池中
避免频繁的创建、关闭
连接池的创建步骤
①src下面写一个druid.properties文件
内容如下:
druid.driverClassName=com.mysql.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/bookshop? useSSL=false&characterEncoding=utf-8
druid.username=root
druid.password=root
druid.initialSize=10
druid.maxActive=50
druid.minIdle=5
druid.maxWait=5000
public class TestDruid {
public static void main(String[] args) {
//1.创建连接池
//方式一:使用dataSource.configFromPropety();要求配置文件中使用druid.前缀
// DruidDataSource dataSource = new DruidDataSource();
// try{
// Properties properties = new Properties();
// InputStream is = TestDruid.class.getClassLoader().getResourceAsStream("druid.properties");
// properties.load(is);
// is.close();
// dataSource.configFromPropety(properties);
// }catch (Exception e){
// throw new RuntimeException(e);
// }
//2.使用工厂创建连接池对象
DruidDataSource dataSource = null;
try {
Properties properties = new Properties();
InputStream is = TestDruid.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
is.close();
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
}catch(Exception e){
throw new RuntimeException(e);
}
for (int i = 0; i < 100; i++) {
try {
Connection conn = dataSource.getConnection();
System.out.println(i + "拿到了" + conn.hashCode());
conn.close();//这个close的意思是把线程还给线程池
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}