1. JDBC
DBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。JDBC是数据库与Java代码的桥梁。
JDBC中定义了操作数据库的各种接口和类型:
增删改基本操作:
(1)获取连接 :
Connection connection = DriverManager.getConnection(url, username, password);
(2)编写SQL语句:
String sql = "insert into user(...) values(...)";
String sql = "delete from user where id =...";
String sql = "update user set name = '' where name = ''";
(3)创建预处理命令对象:
PreparedStatement pst = connection .prepareStatement(sql);
(4)填充参数:
pst.setInt(1,4); //pst.setInt(1,user.getId);
pst.setString(2,"赵六"); //pst.setString(2,user.getName);
(5)执行更新:
pst.executeUpdate(); //返回受影响条数
(6)释放资源
try {
if (rs != null) { //增删改操作无rs
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
查询基本操作:
(1)获取连接
(2)编写SQL语句
(3)创建预处理命令对象
(4)填充参数
(5)执行查询:ResultSet rs = pst.executeQuery(sql);
(6)解析结果集:
List<User> userList = new ArrayList<>();
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
int age = rs.getInt(3);
User user = new User(id,name,age);
userList.add(user);
}
(7)释放资源
2. 抽取基本JDBC中的基本操作 - BaseDao
(1)获取连接
protected Connection getConn(){
try {
//1.加载驱动
Class.forName(DRIVER);
//2.通过驱动管理器获取连接对象
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
(2)释放连接
protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
(3)执行增删改操作,返回受影响数量
protected int executeUpdate(String sql,Object...params){
try {
//获取连接
conn = getConn();
//创建预处理命令对象
psmt = conn.prepareStatement(sql);
//填充参数
if(params!=null && params.length>0){
for(int i = 0;i<params.length;i++){
psmt.setObject(i+1,params[i]);
}
}
//执行更新
return psmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
(4)执行查询操作,返回查询的结果集
//执行查询,返回list
protected List<T> executeQuery(String sql , Object... params){
List<T> list = new ArrayList<>();
try {
//获取连接
conn = getConn();
//创建预处理命令对象
psmt = conn.prepareStatement(sql);
//填充参数
setParams(psmt,params);
//执行查询
rs = psmt.executeQuery();
/*解析结果集
考虑:
1.【pst.setInt(1,user.getId);】第一列未必是int类型;
2. 列数不确定;
3. 封装数据时不知道具体的类的实例对象,无法封装
解决:
1. 列表中指定类,使用泛型 List<T>,在继承该类时指明类型传过来,该类名改为BaseDao<T>
2. 获取传过来的T的类型
(1)获取T的Class对象 entityClass
(2) 创建实例对象 entityClass.newInstance();
(3) 给entity中的所有属性赋值 通过反射技术 setValue 方法
*/
//通过rs可以获取结果集中的元数据(元数据:描述结果集数据的数据,结果集中有哪些列,什么类型...)
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
while(rs.next()){
T entity = (T)entityClass.newInstance();
//要将 columnValue 的值赋给 entity 对象的 columnName 属性
for (int i = 0; i < columnCount; i++) {
String columnName = rsmd.getColumnName(i + 1);//获取列的名字 id
Object columnValue = rs.getObject(i + 1);//给每一列赋值 001
setValue(entity,columnName,columnValue);
}
list.add(entity);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return list;
}
//提取给预处理对象设置参数的方法
private void setParams(PreparedStatement psmt , Object...params) throws SQLException {
if(params!=null && params.length>0){
for(int i = 0;i<params.length;i++){
psmt.setObject(i+1,params[i]);
}
}
}
//通过反射技术给Obj对象的property属性赋propertyValue值
private void setValue(Object obj,String property,Object propertyValue){//对象,属性,属性值
Class clazz = obj.getClass(); //获取Class对象
try {//获取 property 字符串对应的属性名,如"id"去找obj对象中的 id 属性
Field field = clazz.getDeclaredField(property);
if(field!=null){
field.setAccessible(true); //强制访问
field.set(obj,propertyValue); //设置obj对象的field属性的值为propertyValue
}
} catch (NoSuchFieldException | IllegalAccessException e ) {
e.printStackTrace();
}
}
(5)执行查询,返回单个实体对象
//执行查询,返回单个实体对象
protected T load(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
if(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1);
Object columnValue = rs.getObject(i+1);
setValue(entity,columnName,columnValue);
}
return entity ;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
(6)执行复杂查询,返回例如统计结果
protected Object[] executeComplexQuery(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
Object[] columnValueArr = new Object[columnCount];
if(rs.next()){
for(int i = 0 ; i<columnCount;i++){
Object columnValue = rs.getObject(i+1);
columnValueArr[i]=columnValue;
}
return columnValueArr ;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
(7)在添加操作时,获取自增列的值
-----如何获取-----(先判断是否是添加操作)-----
A. 创建pamt时,设置第二个参数
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
B. 执行完更新之后,再去获取结果集,结果集中就包含了自增列的值
psmt.executeUpdate() ;
ResultSet rs = psmt.getGeneratedKeys();
Long id = rs.getLong(1);//再转为int
修改更新操作
protected int executeUpdate(String sql,Object...params){
boolean insertFlag = false;
insertFlag = sql.trim().toUpperCase().startsWith("INSERT"); //如果sql语句是以“insert”开头
try {
//获取连接
conn = getConn();
if(insertFlag == true){ //创建预处理命令对象方式不一样
//创建预处理命令对象
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
}
else{
psmt = conn.prepareStatement(sql);
}
//填充参数
setParams(psmt,params);
//执行更新
int count = psmt.executeUpdate();
rs = psmt.getGeneratedKeys();
if(rs.next()){
//如果是删除、修改操作,返回受影响行数,如果是添加操作,返回的是自增列的值
return ((Long) rs.getLong(1)).intValue();
}
return count;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
BaseDAO类:
public abstract class BaseDAO<T> {
public final String DRIVER = "com.mysql.jdbc.Driver" ;
public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
public final String USER = "root";
public final String PWD = "123456" ;
protected Connection conn ;
protected PreparedStatement psmt ;
protected ResultSet rs ;
//T的Class对象
private Class entityClass ;
public BaseDAO(){
//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
//所以getGenericSuperclass()获取到的是BaseDAO的Class
Type genericType = getClass().getGenericSuperclass();
//ParameterizedType 参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
//获取到的<T>中的T的真实的类型
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
protected Connection getConn(){
try {
//1.加载驱动
Class.forName(DRIVER);
//2.通过驱动管理器获取连接对象
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//给预处理命令对象设置参数
private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
if(params!=null && params.length>0){
for (int i = 0; i < params.length; i++) {
psmt.setObject(i+1,params[i]);
}
}
}
//执行更新,返回影响行数
protected int executeUpdate(String sql , Object... params){ //不定参数
boolean insertFlag = false ;
insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
try {
conn = getConn(); //创建连接
if(insertFlag){
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
}else {
psmt = conn.prepareStatement(sql);
}
setParams(psmt,params);
int count = psmt.executeUpdate() ;
if(insertFlag){
rs = psmt.getGeneratedKeys();
if(rs.next()){
return ((Long)rs.getLong(1)).intValue();
}
}
return count ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
//通过反射技术给obj对象的property属性赋propertyValue值
private void setValue(Object obj , String property , Object propertyValue){
Class clazz = obj.getClass();
try {
//获取property这个字符串对应的属性名 , 比如 "fid" 去找 obj对象中的 fid 属性
Field field = clazz.getDeclaredField(property);
if(field!=null){
field.setAccessible(true);
field.set(obj,propertyValue);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
//执行复杂查询,返回例如统计结果
protected Object[] executeComplexQuery(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
Object[] columnValueArr = new Object[columnCount];
//6.解析rs
if(rs.next()){
for(int i = 0 ; i<columnCount;i++){
Object columnValue = rs.getObject(i+1); //33 苹果 5
columnValueArr[i]=columnValue;
}
return columnValueArr ;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
//执行查询,返回单个实体对象
protected T load(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
if(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
setValue(entity,columnName,columnValue);
}
return entity ;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
//执行查询,返回List
protected List<T> executeQuery(String sql , Object... params){
List<T> list = new ArrayList<>();
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
while(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
setValue(entity,columnName,columnValue);
}
list.add(entity);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return list ;
}
}
3. 执行批处理
psmt.addBatch(); //添加批处理任务
psmt.executeBatch(); //执行批处理任务
psmt.clearBatch(); //清空批处理任务
在url中添加参数 rewriteBatchedStatements=true
4. 数据源连接池
(每次调用basedao,用的时候去获取连接,效率偏低。
采取方式:在程序运行的时候先准备几个连接对象,要用的时候在连接池中取,用完后归还。
响应时间更快,对象利用率更高)
Druid 德鲁伊
(1)加入jar包:druid-1.1.10.jar
(2)代码步骤
A. 建立一个连接池
B. 设置连接池参数
C. 获取连接
public class Demo01Druid {
public static void main(String[] args) throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false");
dataSource.setName("root");
dataSource.setPassword("123456");
//1.被close的连接对象并没有真正关闭,而是将连接状态重新设置为空闲状态,然后放回池子,这样下次获取连接池,这个对象会被重复使用。
//2. 没有被close的连接对象会被一直占有,下次获取连接对象时,不会获取到这个对象。
Connection connection = dataSource.getConnection();
connection.close();
}
}
读取外部的配置文件设置连接池
public class Demo02Druid {
public static void main(String[] args) throws SQLException, IOException {
Properties properties = new Properties();
InputStream is = Demo02Druid.class.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(properties.getProperty("jdbc.driverClassName"));
dataSource.setUrl(properties.getProperty("jdbc.url"));
dataSource.setName(properties.getProperty("jdbc.username"));
dataSource.setPassword(properties.getProperty("jdbc.pwd"));
dataSource.setInitialSize(Integer.parseInt(properties.getProperty("jdbc.initSize"))); //初始化连接池中的连接数量
dataSource.setMaxActive(Integer.parseInt(properties.getProperty("jdbc.maxActive"))); //最大连接数量
dataSource.setMaxWait(Integer.parseInt(properties.getProperty("jdbc.maxWait"))); //最长等待连接时间
Connection connection = dataSource.getConnection();
connection.close();
}
}
jdbc.properties
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username = root
jdbc.pwd = 123456
jdbc.initSize = 2
jdbc.maxActive = 5
jdbc.maxWait = 5000
Druid直接导入properties
public class Demo03Druid {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
InputStream is = Demo03Druid.class.getClass().getClassLoader().getResourceAsStream("jdbc2.properties");
properties.load(is);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
Connection connection = dataSource.getConnection();
connection.close();
}
}
jdbc2.propertise
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false
username = root
password = 123456
initialSize = 2
maxActive = 5
maxWait = 5000
标签:JDBC,rs,jdbc,params,连接池,sql,基本操作,psmt,conn
From: https://www.cnblogs.com/Joyce-mi7/p/16585662.html