1、为什么要使用JDBC?
因为把要数据持久化,持久化数据的最好方式就是把数据保存到数据库,而Java要数据保存到数据,就需要使用JDBC
2、持久化到数据库的技术,唯一的只有JDBC ,其他的所有框架实现的底层都是JDBC,eg:Hibernate, MyBatis,JPA,SpringData JDBC
3、什么是JDBC?
JDBC(Java DataBase Connectivity,Java数据库连接):
是一种用于执行SQL语句(DML,DDL,DQL)的Java API,可以为多种关系数据库(oracle,mysql,SQL server)提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序.
4、结论:以后我们不管使用哪一种数据库,都需要去导入这个数据库给我们提供的jdbc实现的jar包(如mysql:mysql-connector-java-5.1.7-bin.jar)
5、JDBC使用步骤:加(加载驱动)、连(连接数据库)、预(获取预编译对象)、执(执行SQL)、释(释放连接)
//添加示例
public void testAdd() throws ClassNotFoundException, SQLException {
//1.注册驱动[反射机制:jvm 拿到Mysql已经写好的驱动类]
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接对象
//url可简写为jdbc:mysql:///数据库名
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名", "用户名", "密码");
//3.获得预编译对象,准备执行Sql
Statement statement = conn.createStatement();
//4执行Sql
String sql = "insert into user(name,sex,phoneNum) value ('孙孙',false,'666')";
System.out.println(sql);
statement.execute(sql);//执行sql语句
//5.释放资源
statement.close();//关闭
conn.close();
}
6、ResultSet:保存查询返回的数据
7、PreparedStatement与createStatement的区别
(1)Statement在创建语句对象,不需要传入sql;而PreparedStatement是预处理语句,需要传入sql,这个时候数据库已经收到sql语句,编译完了(用?先代替参数占个位,所以?叫占位符),等待参数进行操作,所以比createStatement的速度快;
(2)所以,在执行sql语句的时候,Statement 需要传入sql;PreparedStatement在执行sql语句时候,不需要传入sql;
(3)PreparedStatement使用占位符?进行赋值的方式(ps.setObject(index,value)),而createStatement是通过拼接+的方式
(4)所以,PreparedStatement是安全的,createStatement是不安全的(万能密码:’ or 1=1 or '),存在sql注入
(5)联系:PreparedStatement是Statement的子接口
8、dao层抽取工具:增、删、查、改使用一个方法
public List<User> execute(String sql, Object... arr) {
ArrayList<User> userList = new ArrayList<User>();
Connection connection = null;
PreparedStatement ps =null;
try {
connection = DBCPUtil2.getConnection();
ps = connection.prepareStatement(sql);
for (int i = 0; i < arr.length; i++)
ps.setObject(i+1, arr[i]);
if (sql.contains("select")) {
//是select,获取结果集,放到集合里,返回集合
ResultSet eq = ps.executeQuery();
while (eq.next()) {
userList.add(new User(eq.getInt("id"), eq.getString("name"), eq.getBoolean("sex"), eq.getString("phoneNum"), eq.getString("pwd")));
}
return userList;
}
ps.execute();//是DML操作,执行即可,最后返回null
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
9、事务:
指一组逻辑操作单元,使数据从一种状态变换到另一种状态
ACID属性:Atomic原子性、Consistency一致性、Isolation隔离性和Durability持久性
/**
* 转账示例
*/
public void testTransaction() {
Connection conn = null;
Statement cs =null;
try {
conn = JDBCUtil.getConnection();//一个连接就是一个事务
conn.setAutoCommit(false);//事务默认是自动提交,所以设置为手动提交
cs = conn.createStatement();
String sql="update user set money=money-10 where name=shp";//转钱:转方
cs.execute(sql);
System.out.println(1/0);//模仿异常发生
sql="update user set money=money+10 where name=heping";//转钱:收方
cs.execute(sql);
conn.commit();//在操作完成后提交事务
} catch (Exception e) {
try {
conn.rollback();//发生异常就事务回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
JDBCUtil.close(conn, cs, null);
}
}
10、解决数据库配置信息硬编码问题,通过DHCP实现连接池,解析资源文件
导包commons-dbcp-1.3.jar和commons-pool-1.5.6.jar
(1)连接池
public class DBCPUtil {
static Properties properties = new Properties();
static BasicDataSource bds = new BasicDataSource();//BasicDataSource
static{
try(
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
) {
properties.load(is);//解析资源文件,解决硬编码问题
bds.setDriverClassName(properties.getProperty("driverClassName"));
bds.setUrl(properties.getProperty("url"));
bds.setUsername(properties.getProperty("username"));
bds.setPassword(properties.getProperty("password"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
return bds.getConnection();//向连接池获取连接
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
(2)工厂模式
public class DBCPUtil2 {
static Properties properties = new Properties();
static DataSource bds;
static{
try(
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
) {
properties.load(is);//解析资源文件,解决硬编码问题
//工厂已定义好字段名,所以想要正确获取,就应该在配置文件中的配置参数写对应的名字
bds=BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
return bds.getConnection();//向连接池获取连接
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}