栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用JDBC连接数据库及书写套路

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用JDBC连接数据库及书写套路

1.JDBC简介

jdbc(Java Database Connectivity)

在C语言的Odbc基础上发展而来,是最早的ORM(Object Relation Mapping对象映射关系)工具,可以使用面向对象的Java代码
对关系型数据库进行操作。
ORM工具随着不断的发展衍生出了很多框架那么大部分框架都是在JDBC基础上发展而来,JDBC是几乎所有框架的基础,也是效率最高的ORM工具
JDBC是第一方技术,所有的接口等全部放置在java.sql包中

全手动 JDBC
半自动 myBatis
全自动 Hibernate

1)创建关系表
2)创建实体类
A:一般放置在com.etoak.po包中或者bean包中
B:尽量使用包装类封装字段,字段名对应
C:必须书写空参构造方法,酌情覆盖有参构造方法
D:酌情覆盖toString()
3)创建工厂类
A:工厂类一般放置在com.etoak.factory包中,此类链接数据库
B:加载驱动,只需要加载一次放置在静态初始化块中
C:封装一个方法返回链接
4)书写dao层
A:dao层全部放置在com.etoak.dao包中
B:接口用来设置需要被实现的方法
C:实现类实现接口中的方法

创建数据表
DROp table if EXISTS  person;
CREATE  table person (
  id     INT PRIMARY KEY AUTO_INCREMENT,
  name   VARCHAr(10) NOT NULL,
  pass   VARCHAr(10) NOT NULL,
  age    INT,
  salary DOUBLE,
  birth  DATE
);
insert INTO person VALUES (null,'elena','12345',20,5000.00,'1990-06-03');
insert INTO person VALUES (null,'penny','123465',30,6000.00,'1993-06-13');
insert INTO person VALUES (null,'aleric','1234545',40,7000.00,'1992-06-05');
insert INTO person VALUES (null,'bonnie','1432345',20,3000.00,'1996-06-03');
insert INTO person VALUES (null,'matt','123345',24,15000.00,'1997-06-04');
insert INTO person VALUES (null,'damon','123445',23,25000.00,'1992-06-04');
insert INTO person VALUES (null,'用户名','1232245',29,5000.00,'1998-07-01');
1. JavaBean实体类

如果一个Java类仅仅封装了属性,没有其他方法,则称之为POJO类或实体类,好像也叫作JavaBean,通常放置在com.xxx.po 或者 com,xxx.bean 包中

这个类中封装的属性必须对用数据库中的字段,必须覆盖空参的构造方法,酌情覆盖全参构造方法,酌情覆盖toString()方法

public class Person{
    //使用包装类封装字段,必须对应表中的字段
	private Integer id;
	private String name;
	private String pass;
	private Integer age;
	private Double salary;
	private Date birth;
    
    
	public Person() {
	}
    
	public Person(Integer id, String name, String pass, Integer age, Double salary, Date birth) {
		this.id = id;
		this.name = name;
		this.pass = pass;
		this.age = age;
		this.salary = salary;
		this.birth = birth;
	}
    //各个属性的get和set方法
    //看需求是否覆盖 toString() 方法
}
2. 工厂类

一般放置在**com.xxx.factory包中** 1.加载驱动

static{
    try{
        Class.forName("com.mysql.jdbc.Driver");
    }catch(Exception e){
        e.printStackTrace();
    }
}
2.获取链接
public static Connection getConn(){
        try{
            //2.加载链接
            
            return DriverManager.getConnection("jdbc:mysql:///et1912","root","dream");
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
3.释放资源
public static void close(ResultSet rs, Statement st,Connection con){
		try {
			if(rs!=null)
				rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if(st!=null)
					st.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				try {
					if(con!=null)
						con.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
	}

代码

package com.etoak.factory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Factory {
	
	static{
		try {
			//使用反射类加载的方式加载驱动
			//不同品牌的驱动不同,需要导入数据库厂商提供的jar包
			Class.forName("com.mysql.jdbc.Driver");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}


	
	public static Connection getCon(){
		try {
			
			return DriverManager.getConnection(
			"jdbc:mysql:///et1912","root","etoaketoak");
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	
	public static void close(ResultSet rs, Statement st,Connection con){
		try {
			if(rs!=null)
				rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if(st!=null)
					st.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				try {
					if(con!=null)
						con.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
	}
}
3.dao持久化层

dao(Data Access Object) 数据访问对象通常放置在**com.xxx.dao包下** 1. 接口

public interface PersonDaoIf {

	//添加一个用户
	public boolean addPerson(Person per);

	//根据id删除一个用户
	public boolean delPersonById(Integer id);

	//拿取全部用户
	public List queryAll();

	//根据用户名查询
	public boolean queryName(String name);

	//根据用户名和密码查询
	public Person queryPerson(String name,String pass);

	//修改用户资料
	public boolean updatePerson(Person per);

}
public interface PersonDaoIf2 {
	//1添加用户
	public boolean addPerson(Person per);

	//2根据id删除
	public boolean delPersonById(Integer id);

	//3根据name删除
	public boolean delPersonByName(String name);

	//4拿取全部
	public List queryAll();

	//5姓名查重
	public boolean queryName(String name);

	//6登录查询
	public Person queryPerson(String name,String pass);

	//7拿取总记录数
	public Integer queryCount();

	//8分页查询
	public List queryPage(Integer index,Integer max);

	//9姓名模糊分页查询
	public List queryNameLikePage(String args,Integer index,Integer max);

	//10条件分页查询
	public List queryLikePage(Person per,Integer index,Integer max);

	//11批量删除
	public boolean multiDel(String[] args);

	//12修改
	public boolean updatePerson(Person per);
}

2.接口实现类[Statement]

创建 PersonDaoIf 接口的实现类 PersonDaoImpl右键空白处 **(或者alt + insert)**选择 Implements Method,实现接口中的抽象方法

public class PersonDaoImpl implements PersonDaoIf{
    //设置连接
    Connection conn;
    //设置执行器
    Statement st;
    //结果集
    ResultSet rs;
    @Override
	public boolean addPerson(Person per) {
		try {
			//书写sql语句
			
			String sql =
			"insert into person values (null,'"+per.getName()+"','"+per.getPass()+"',"+per.getAge()+","
			+per.getSalary()+",'"+new SimpleDateFormat("yyyy-MM-dd").format(per.getBirth()) +"')";

			//获取连接
			con = Factory.getCon();

			//拿取执行器
			st = con.createStatement();

			//执行器根据sql语句调用方法
			return st.executeUpdate(sql)==1;

		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			//不管是否执行正常都要释放资源
			Factory.close(null,st,con);
		}
	}
}
存在的安全隐患

当传入的是一个恒等的条件表达式的时候,语句相当于查找全表数据可以被SQL注入 3.接口实现类[PreparedStatement]

创建类PersonDaoImpl2实现PersonDaoIf2接口PreparedStatement是Statement的子类使用PreparedStatement执行器时,使用 ? 先进行站位,后填充填充日期类型时,需要用**new java.sql.Date(xxx.getDate().getTime())**

package com.etoak.dao;

import com.etoak.factory.Factory;
import com.etoak.po.Person;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class PersonDaoImpl2 implements PersonDaoIf2 {

	Connection con;
	Statement st;
	
	PreparedStatement pst;
	ResultSet rs;

	@Override
	public boolean addPerson(Person per) {
		try {
			
			String sql = "insert into person values (null,?,?,?,?,?)";
			con = Factory.getCon();
			//获取执行器的同时,加载带有?占位符的sql语句
			pst = con.prepareStatement(sql);
			//由于存在占位符所以必须填充
			
			pst.setString(1,per.getName());
			pst.setString(2,per.getPass());
			pst.setInt(3,per.getAge());
			pst.setDouble(4,per.getSalary());
			
			pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			//长按ctrl或者command键可以溯源
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean delPersonById(Integer id) {
		try {
			String sql = "delete from person where id = ?";
			con = Factory.getCon();
			//获取执行器的同时加载sql语句
			pst = con.prepareStatement(sql);
			pst.setInt(1,id);
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean delPersonByName(String name) {
		try {
			String sql = "delete from person where name = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			return pst.executeUpdate()>=1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public List queryAll() {
		try {
			String sql = "select * from person";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			rs = pst.executeQuery();
			List list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt(1),
						rs.getString(2),rs.getString(3),rs.getInt(4)
				,rs.getDouble(5),rs.getDate(6)));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public boolean queryName(String name) {
		try {
			String sql = "select * from person where name = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			return pst.executeQuery().next();
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public Person queryPerson(String name, String pass) {
		try {
			String sql = "select * from person where name = ? and pass = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			pst.setString(2,pass);
			rs = pst.executeQuery();
			if(rs.next()){
				return new Person(rs.getInt(1),
						rs.getString(2),rs.getString(3)
				,rs.getInt(4),rs.getDouble(5),rs.getDate(6));
			}
			return null;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public Integer queryCount() {
		try {
			String sql = "select count(*) from person";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			rs = pst.executeQuery();
			
			rs.next();
			return rs.getInt(1);
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public List queryPage(Integer index, Integer max) {
		try {
			
			String sql = "select * from person limit ?,?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setInt(1,index);
			pst.setInt(2,max);
			rs = pst.executeQuery();
			List list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt(1),
						rs.getString(2),
						rs.getString(3),
						rs.getInt(4),
						rs.getDouble(5),
						rs.getDate(6)));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	//根据姓名模糊查询并且分页
	@Override
	public List queryNameLikePage(String args, Integer index, Integer max) {
		try {
			String sql = "select * from person where name like ? limit ?,?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			//对左模糊右模糊进行拼接
			pst.setString(1,"%"+args+"%");
			pst.setInt(2,index);
			pst.setInt(3,max);
			rs = pst.executeQuery();
			List list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt("id")
				,rs.getString("name")
				,rs.getString("pass")
				,rs.getInt("age")
				,rs.getDouble("salary")
				,rs.getDate("birth")));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public List queryLikePage(Person per, Integer index, Integer max) {
		return null;
	}

	
	@Override
	public boolean multiDel(String[] args) {
		try {
			String sql = "delete from person where id in (";
			String sum = "";
			for(int i = 0;i=1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean updatePerson(Person per) {
		try {
			String sql =
			"update person set name = ?,pass = ?,age = ?,salary = ?,birth = ? where id = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,per.getName());
			pst.setString(2,per.getPass());
			pst.setInt(3,per.getAge());
			pst.setDouble(4,per.getSalary());
			pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
			pst.setInt(6,per.getId());
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}
}
1.书写套路注意事项
    Statement执行器
//在实现的方法中,第一步现获取连接
conn = Factory.getConn();
//第二步,获取执行器
st = conn.createStatement();
//第三步。书写Sql语句,这里可以先将SQL语句写完整之后在根据是否是字符类型的加双引号
String sql = "select * from person";
//如果没有返回结果集,则返回执行结果,
//此方法返回的是受影响的行数,返回值为int
return st.executeUpdate(sql) > 0;
//如果有返回结果集,则第四步,获得结果集
rs = st.executeQuery(sql);
//第五步,创建一个新的空集合,给定泛型确保只能存储该类型的对象
List list = new ArrayList<>();
//第六步 把结果集中的结果依次添加到空集合中
while(rs.next()){
    list.add(new Person(rs.getInt(1),...));
}
//第七步,关闭连接
Factory.closeConn(rs,st,conn);
    PreparedStatement执行器
//1获取连接
conn = Factory.getConn();
//2.书写sql语句,先使用占位符 ? 来填充
String sql = "select * from person where name like ? limit ?,?";
//3.获取执行器d的同时把sql语句传入
pst = conn.preparedStatement(sql);
//4.给占位符传入相应的值,第一个参数代表是sql语句中第几个问号,第二个参数代表传入的值
//4.1 模糊查询时拼接字符串
pst.setString(1,"%" + per.getName() + "%");
//4.2传入其他参数
pst.setInt(2,per.getAge());
//4.3 Date类型,因为util.Date不能拼接sql语句,所以要转化成sql.Date
pst.setDate(3,new java.sql.Date(per.getBirth().getTime()));
//5.执行
pst.executeQuery();
2. Date注意事项
    执行sql语句拼接Date时

java.util.Date无法和字符串直接通过+拼接成sql语句

可以有以下两种方式

​ 1)将java.util.Date转换为java.sql.Date,可以直接拼接

​ 2)将java.util.Date转换为字符串

String sql = "insert into person values('"+ new SimpleDateFormat("yyyy-MM-dd").format(Date) +"')"
    创建对象把String转换成Date类型时
Person per = new Person(new SimpleDateFormat("yyyy-MM-dd").parse("1999-01-01"));
    PreparedStatement传入Date
pst = conn.preparedStatement(sql);
pst.setDate(1,new java.sql.Date(per.getBirth().getTime()));
4. 测试
package com.etoak.test;

import com.etoak.factory.Factory;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class Test {
	public static void main(String[] args) {
		try {
			//调用工厂获取连接,从而链接数据库
			Connection con = Factory.getCon();
			
			if(con==null){
				System.out.println("链接失败!!");
				return;
			}
			System.out.println("链接成功!!");

			
			Statement st = con.createStatement();

			String dml1 = "insert into person values (null,'测试1','12345',30,2000.00,'2000-03-03')";
			String dql1 = "select * from person";

			
			//int count = st.executeUpdate(dml1);
			//System.out.println(count);

			ResultSet rs = st.executeQuery(sql1);
			
			while(rs.next()){
				
				
				System.out.println("ID:"+rs.getInt("id")+"t姓名:"
				+rs.getString("name")+"t密码:"+rs.getString("pass")
				+"t年龄:"+rs.getInt("age")+"t薪资:"+rs.getDouble("salary")
				+"t生日:"+rs.getDate("birth"));
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
1. 注意点
    创建执行器

通常有两种 Statement , PreparedStatement

返回类型执行器方法解释
booleanexecute()如果执行DML语句则返回true
如果执行DML语句,则返回false,但是依然可以执行
此方法使用较少
intexecuteUpdate()如果执行DQL语句立即报错
执行DML语句则返回受影响的记录数
ResultSetexecuteQuery()如果执行DML语句立即报错
执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值
int[]executeBatch()执行批处理,一次执行多条SQL语句
语言全称包含内容
SQLStructured Query Language,结构化查询语言DDL、DML、DQL、DCL、TCL
DDLData Definetion Language,数据定义语言create(新建)、alter(修改)、drop(删除)、truncate(截断)
DMLData Manipulation Language,数据操纵语言insert (插入)、update(修改)、delete(删除)
DQLData Query Language,数据查询语言select(查询)
DCLData Control Language数据控制语言grant(授权)、revoke(取消授权)
TCLTranslation Control Language事务控制语言commit(提交)、rollback(回滚)、savepoint(保存还原点),只会影响DML操作。
    拿取有效数据

要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析

不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格, 存在表头,永远不为null, 存在一个 boolean next() 结果集类似一个表格,

默认指针指向第一行表头,当我们调用 rs .next() 时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false所以我们可以根据.next()方法是否返回true来判断是否存在有效数据

rs = st.executeQuery(sql);
while(rs.next()){
    //TODO
}
    拿取数据

可以通过 get数据类型(列数) 或者 get数据类型(列名)来拿取

Integer id = rs.getInt(1);
String name = rs,getString("name");
2.执行器的executeBatch()方法

首先需要关闭mysql的自动提交事务,conn.setAutoCommit(false); 出错时不会提交用 addBatch(sql)方法 把要执行的SQL语句挨个放进执行器中执行方法并提交打开MySQL的自动提交

public class TestBatch {
	public static void main(String[] args) {
		try {
			//获取连接
			Connection con = Factory.getCon();
			//关闭mysql的自动提交事务
			con.setAutoCommit(false);
			//获取执行器
			Statement st = con.createStatement();

			//设置要批处理得sql
			//注意批处理不能执行dql语句
			String dml1 = "insert into person values (null,'elena','12345',30,5000.00,'1990-03-01')";

			String dml2 = "insert into person values (null,'damon','33345',20,6000.00,'1993-03-01')";

			String dml3 = "insert into person values (null,'stefan','53345',17,4000.00,'1992-03-01')";

			String dml4 = "delete from person where id = 1";

			//将要执行的sql语句添加进缓存中
			//这里每条sql语句都类似一个子弹,此处压入弹夹
			st.addBatch(dml1);
			st.addBatch(dml2);
			st.addBatch(dml3);
			st.addBatch(dml4);

			//进行批处理操作
			
			int[] count = st.executeBatch();
			//提交事务
			con.commit();
			//恢复自动提交
			con.setAutoCommit(true);

			for(int i:count){
				System.out.println("更改的记录数是~~~~》"+i);
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

5. Statement和PreparedStatement的区别
    相同点

两者都为接口

public interface Statement implements Wrapper
public interface PreparedStatement implements Statement PreparedStatement是Statement的子类

    不同点

①:Statem只能执行静态语句; PreparedStatement 可以还行IN参数的sql语句,所谓IN参数是指,sql语句可以进行字段等数据的更改
并不是一个固定的语句。

②PreparedStatement存在一个强大缓存区,可以对sql语句
进行预编译,在执行相同的sql语句时,PreparedStatement
将语句加载进缓存区,仅仅编译一次,当第二次执行此语句时
不需要再次进行编译,也就是说相同的sql语句执行多条
仅仅编译一次,PreparedStatement仅对改动数据进行修改
而不再进行编译;
Statement只要语句发生了改变,则必须重新进行编译

③:PreparedStatement支持对sql语句使用?占位符,从而对
sql语句进行字段参数的修改,降低了开发难度,并且从根本上杜绝了
sql注入安全隐患

④如果sql语句不需要多次执行,或者?过多,则效率可能较
Statement低

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/756119.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号