什么是JDBC
JDBC(Java Database connecivity) Java连接数据库的规范(标准),可以使用java语言连接数据库完成CRUD操作
JDBC的核心思想
Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式,有数据库厂商提供的驱动实现类(Driver数据库驱动)
JDBC开发步骤
我的mysql版本是8.0.20版本的和5.7以前的连接有点区别
DML
1.注册驱动
加载驱动
加载驱动类到内存中,用于访问数据库
Class.forName("驱动名")
使用Class.forName("com.mysql.jdbc.Driver");手动加载字节码文件到JVM中
Class.forName("com.mysql.cj.jdbc.Driver");//加载驱动 5.7以后要加cj
SQLServer:
com.microsoft.sqlserver.jdbc.SQLServerDriver
MySQL:
com.mysql.jdbc.Driver (5.7版本以下)
com.mysql.cj.jdbc.Driver (5.7以上)
2.连接数据库 建立连接
获得连接
Connection DriverManager.getConnection(URL,用户,密码)
通过DriverManager.getConnection(url,user,password) 获取数据库连接对象
URL: jdbc:mysql://localhost:3306/数据库名称?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username : root
password: 123456
SQLServer:
jdbc:sqlserver://数据库主机名:1433;DatabaseName=数据库名
MySQL:
jdbc:mysql://数据库主机名:3306/数据库名?serverTimezone=UTC 5.7以后
jdbc:mysql://数据库主机名:3306/数据库名 5.7以前
useUnicode=true&characterEncoding=utf8是为了防止中文乱码的
3.获取发送sql的对象
通过 Connection对象获得Statement对象,用于对数据库进行通用访问
Statement statement=conn.createStatement();
4.执行SQL 语句
执行SQL语句并接收执行结果
int i = statement.executeUpdate("INSERT INTO bank(id,money) VALUES(4,2000)");
注意在编写DML语句时,一定要注意字符串参数的符号是单引号’值’
DML语句增删改时,返回受影响的行数(int类型)
DQL语句:查询时,返回结果数据(ResultSet结果集)
5.处理结果
if(i>0){
System.out.println("添加成功");
}
else{
System.out.println("添加失败");
}
DML:返回的是受影响的行数:逻辑判断,方法返回
DQL:返回的是查询结果集:迭代,以此获取
6.释放资源
遵循先开后关的原则,释放使用到的资源对象
statement.close();
conn.close();
综合DML语句
package JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class jdbc02 {
public static void main(String[] args) {
Connection conn=null;
Statement statement=null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获得连接对象
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3?serverTimezone=UTC","root","123456");
//获得执行sql对象
statement = conn.createStatement();
//执行sql语句,并接受结果
int i = statement.executeUpdate("INSERT INTO bank(id,money) VALUES(4,2000)");
//处理结果
if(i>0){
System.out.println("添加成功");
}
else{
System.out.println("添加失败");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
finally {
try {
//释放资源
statement.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
DQL
ResultSet rs = statement.executeQuery(sql);
rs = st.executeQuery("select * from bank");
遍历ResultSet中的数据
ResultSet以表(table)结构进行临时结果的存储,通过JDBC API 将其中数据进行依次获取
数据行指针: 初始位置在第一行数据前,每调用依次boolean next()方法 ResultSet的指针向下移动一行,结果为true表示当前行有数据。
rs.getXxx(整数) 代表根据列的编号顺序获得,从1开始
rs.getXxx(列名) 代表根据列名获得
遍历结果集
while(rs.next()){
int id = rs.getInt("id");
int money = rs.getInt("money");
System.out.println("id:"+id+"\tmoney:"+money);
}
注意:列的编号从1开始
DQL综合
package JDBC;
import java.sql.*;
public class jdbc03 {
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获得连接对象
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3?serverTimezone=UTC","root","123456");
st = conn.createStatement();
//执行sql语句,并接受结果
rs = st.executeQuery("select * from bank");
// 遍历结果集
while(rs.next()){
int id = rs.getInt("id");
int money = rs.getInt("money");
System.out.println("id:"+id+"\tmoney:"+money);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
try {
// 关闭资源
rs.close();
st.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
常见的错误
SQL注入问题
CREATE TABLE login(
username VARCHAR(20) UNIQUE NOT NULL,
PASSWORD VARCHAR(20) NOT NULL
)
INSERT INTO login(username,PASSWORD) VALUES('zhangsan','1234')
SELECT * FROM login WHERE username='zhangsan' AND PASSWORD='1234'
package JDBC;
import java.sql.*;
import java.util.Scanner;
public class jdbc04 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名");
String username=sc.next();
System.out.println("请输入密码");
String password=sc.next();
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3?serverTimezone=UTC", "root", "123456");
st= conn.createStatement();
rs= st.executeQuery("SELECT * FROM login WHERE username='"+username+"' AND PASSWORD='"+password+"'");
if (rs.next()){
System.out.println("登录成功");
}
else{
System.out.println("登录失败");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
finally {
try {
rs.close();
st.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
当密码是 abc’ or 1=1;#的时候无论密码输什么都能登录成功
为了解决sql注入问题所以我们要采用PreparedStatement
PreparedStatement作用
预编译SQL语句,效率高
安全,避免SQL注入
可以动态的填充数据,执行多个同构的sql语句
参数标记
预编译SQL语句
pst = conn.prepareStatement("select * from login where username=? and password=?");
注意:JDBC中所有参数都由?符号站位,这被称为参数标记,在执行sql语句之前必须为每个参数提供值
动态参数绑定
pst.setXxx(下标,值)参数下标从1开始,为指定参数下标绑定值
//预编译sql语句
pst = conn.prepareStatement("select * from login where username=? and password=?");
pst.setString(1,"zhangsan");
pst.setString(2,"1234");
`Connection`接口:与特定数据库的连接(会话)。
`PreparedStatement`接口:表示预编译的 SQL 语句的对象。SQL 语句被预编译并存储在 `PreparedStatement`
对象中。然后可以使用此对象多次高效地执行该语句。
`ResultSet`接口:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
`ResultSet` 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。
`next` 方法将光标移动到下一行;因为该方法在 `ResultSet` 对象没有下一行时
返回 `false`,所以可以在 `while` 循环中使用它来迭代结果集。
Statement与PreparedStatement的区别
1. PreparedStatement是预编译的,对于多次执行的SQL可以大大提高效率。而Statement不行
2. PreparedStatement可以通过占位符的方式解决SQL注入的问题,而Statement不行
3. 二者SQL的传入位置不同
封装工具类
重用工具类实现
封装获取连接,释放资源两个方法
提供 public static Connection getconnection(){} 方法
提供 public static void closeall(Connection conn,Statement stm ResultSet rs)
package JDBC;
import java.sql.*;
public class DBUtils {
static { //静态代码块,类加载时加载只加载一次
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getconnection(){
Connection conn=null;
try {
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/db3?serverTimezone=UTC","root","123456");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
//释放资源
public static void closeall(Connection conn, PreparedStatement pst, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(pst!=null){
try {
pst.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
跨平台工具类的实现
在src目录下创建db.properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db3?serverTimezone=UTC
username=root
password=123456
以后可以直接修改配置文件而不需要修改其他地方
package JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DButil {
//存储配置文件的map
private static final Properties PROPERTIES=new Properties();
//静态代码块仅在类加载的时候加载且仅加载一次
static {
//通过类的方法获得流
InputStream is = DButil.class.getResourceAsStream("/db.properties");
try {
//通过流将配置文件加载到properties集合中
PROPERTIES.load(is);
Class.forName(PROPERTIES.getProperty("driver"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getconnection(){
Connection conn=null;
try {
conn=DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("username"),PROPERTIES.getProperty("password"));
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
public static void closeall(Connection conn, PreparedStatement pst, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(pst!=null){
try {
pst.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
ORM
ORM(Object Relational Mapping)
从数据库查询到的结果集(resultset)在进行遍历时,取出的都是零散的数据,在实际应用开发中,我们需要将零散的数据进行封装整理
实体类(entity)零散数据的载体
一行数据中,多个零散的数据进行整理
通过entity的规则对表中的数据进行对象封装
表名=类名
列名=属性名
提供各个属性的get set 方法
提供无参构造方法(视情况添加有残构造方法)
ORM应用
user实体类
package JDBC;
public class userentity {
private String username;
private String password;
public userentity() {
}
public userentity(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "userentity{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
package JDBC;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class userTest {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
List<userentity> list=new ArrayList();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn=DButil.getconnection();
pst = conn.prepareStatement("select * from login");
rs = pst.executeQuery();
while (rs.next()){
String username = rs.getString("username");
String password = rs.getString("password");
userentity user = new userentity(username, password);
list.add(user);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,rs);
}
for (userentity u:list){
System.out.println(u);
}
}
}
DAO
DAO数据访问对象
DAO实现了业务逻辑与数据库相分离
对同一张表所有操作封装在XxxDaoImpl对象中
根据增删改查的不同功能实现具体的方法(insert update delete select selectall)
数据库
首先创建一张表Person
CREATE TABLE person
(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
age INT NOT NULL,
borndate DATE,
emall VARCHAR(20),
address VARCHAR(20)
)
封装实体类
package Dao;
import java.util.Date;
public class personentity {
package Dao;
import java.util.Date;
public class personentity {
private int id;
private String name;
private int age;
private Date borndate;
private String email;
private String address;
public personentity() {
}
public personentity(String name, int age, Date borndate, String email, String address) {
this.name = name;
this.age = age;
this.borndate = borndate;
this.email = email;
this.address = address;
}
public personentity(int id, String name, int age, Date borndate, String emall, String address) {
this.id = id;
this.name = name;
this.age = age;
this.borndate = borndate;
this.email = email;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBorndate() {
return borndate;
}
public void setBorndate(Date borndate) {
this.borndate = borndate;
}
public String getEmail() {
return email;
}
public void setEmall(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "personentity{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", borndate=" + borndate +
", email='" + email + '\'' +
", address='" + address + '\'' +
'}';
}
}
}
Date 工具类
数据库存储的类型为java.sql.Date 而我们java应用层存储日期类型为java.util.Date,当我们java应用程序插入带有日期的数据到数据库中时需要转换
java.util.Date
java语言常规应用层面的日期类型,可以通过字符串创建对应的时间对象
无法直接通过JDBC插入到数据库
java.sql.Date
不可以通过字符串创建对应的时间对象,只能通过毫秒值创建对象
可以直接通过JDBC插入到数据库
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//指定日期格式
String s="2020-10-10 08:08:08";
try {
Date date = sdf.parse(s);//将字符串解析成日期类型
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
String s1 = sdf.format(new Date());//将日期格式化字符串
System.out.println(s1);
Date工具类封装
package Dao;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Dateutils {
public static final SimpleDateFormat sdf=new SimpleDateFormat("yy-MM-dd");
public static java.util.Date strtoutildate(String str){
try {
Date date = sdf.parse(str);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
public static java.sql.Date utiltosqldate(java.util.Date date){
return new java.sql.Date(date.getTime());
}
public static String utildatetostr(java.util.Date date){
String format = sdf.format(date);
return format;
}
}
编写DaoImpl类
提供增删改查方法完善jdbc开发步骤,完善功能
package Dao;
import JDBC.DBUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class personDaoImpl {
public int insert(personentity person){
int count=0;
Connection conn=null;
PreparedStatement pst=null;
conn = DButils.getconnection();
String sql="insert into person(name,age,borndate,email,address) values(?,?,?,?,?);";
try {
pst = conn.prepareStatement(sql);
pst.setString(1,person.getName());
pst.setInt(2,person.getAge());
pst.setDate(3,Dateutils.utiltosqldate(person.getBorndate()));
pst.setString(4,person.getEmail());
pst.setString(5,person.getAddress());
count = pst.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DButils.closeall(conn,pst,null);
}
return 0;
}
public int update(personentity person) {
Connection conn=null;
PreparedStatement pst=null;
int count=0;
conn= DBUtils.getconnection();
String sql="update person set name=?,age=?,borndate=?,email=?,address=? where id=?";
try {
pst = conn.prepareStatement(sql);
pst.setString(1,person.getName());
pst.setInt(2,person.getAge());
pst.setDate(3,Dateutils.utiltosqldate(person.getBorndate()));
pst.setString(4,person.getEmail());
pst.setString(5,person.getAddress());
pst.setInt(6,person.getId());
count= pst.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,null);
}
return 0;
}
public int delete(int id){
Connection conn=null;
PreparedStatement pst=null;
int count=0;
String sql="delete from person where id=?;";
conn=DBUtils.getconnection();
try {
pst = conn.prepareStatement(sql);
pst.setInt(1,id);
count = pst.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,null);
}
return 0;
}
public personentity select(int id){
personentity person=null;
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
String sql="select * from person where id=?;";
try {
conn=DBUtils.getconnection();
pst= conn.prepareStatement(sql);
pst.setInt(1,id);
rs= pst.executeQuery();
if(rs.next()){
int id1 = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Date borndate = rs.getDate("borndate");
String email = rs.getString("email");
String address = rs.getString("address");
person = new personentity(id1, name, age, borndate, email, address);
return person;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,rs);
}
return person;
}
public List<personentity> selectall(){
List<personentity> personentities = new ArrayList<>();
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
String sql="select * from person";
try {
conn=DBUtils.getconnection();
pst= conn.prepareStatement(sql);
rs=pst.executeQuery();
while (rs.next()){
int id1 = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
Date borndate = rs.getDate("borndate");
String email = rs.getString("email");
String address = rs.getString("address");
personentity person = new personentity(id1, name, age, borndate, email, address);
personentities.add(person);
}
return personentities;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,rs);
}
return personentities;
}
}
service业务逻辑层
代表用户完成一个业务的功能,可以由一个或多个DAO的调用组成(软件提供的一个功能都能叫业务)
编写service实现转账功能
事务
在JDBC中,获得Connection对象开始事务–提交或回滚事务–关闭连接 其他事务策略是
conn.setAutoCommit(false); //true等价于1,false等价于0
conn.commit();//手动提交事务
conn.rollback();//手动回滚事务
转账业务
account实体类
package account;
public class Account {
private String cardID;
private String password;
private String name;
private double balance;
public Account() {
}
public Account(String cardID, String password, String name, double balance) {
this.cardID = cardID;
this.password = password;
this.name = name;
this.balance = balance;
}
public String getCardID() {
return cardID;
}
public void setCardID(String cardID) {
this.cardID = cardID;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"cardID='" + cardID + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", balance=" + balance +
'}';
}
}
AccountDaoImpl类
package account;
import JDBC.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AccountDaoImpl {
public int insert(Account account){
return 0;
}
public int delete(String cardID){
return 0;
}
public int update(Account account){
int count;
Connection conn=null;
PreparedStatement pst=null;
conn=DBUtils.getconnection();
String sql="update account set password=?,name=?,balance=? where cardID=?";
try {
pst=conn.prepareStatement(sql);
pst.setString(1,account.getPassword());
pst.setString(2,account.getName());
pst.setDouble(3,account.getBalance());
pst.setString(4,account.getCardID());
count=pst.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,null);
}
return 0;
}
public Account select(String cardID){
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
Account account=null;
conn= DBUtils.getconnection();
String sql="select * from account where cardID=?";
try {
pst=conn.prepareStatement(sql);
pst.setString(1,cardID);
rs = pst.executeQuery();
if(rs.next()){
String id = rs.getString("cardID");
String password = rs.getString("password");
String name = rs.getString("name");
double balance = rs.getDouble("balance");
account=new Account(id,password,name,balance);
}
return account;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(conn,pst,rs);
}
return null;
}
}
AccountserviceImpl 类
package account;
import JDBC.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
public class AccountserviceImpl {
public void transfer(String fromID,String password,String toID,double money) throws SQLException {
//1.接收传递参数 转账的卡号 密码 被转的卡号 转账的金额
//2.组织完善业务功能
AccountDaoImpl accountDao = new AccountDaoImpl();
Connection conn=null;
try {
//建立一个数据库连接
conn= DBUtils.getconnection();
//开启事务 并且关闭事务的自动提交
conn.setAutoCommit(false);
//2.1验证fromID是否存在
Account account = accountDao.select(fromID);
if(account==null){
throw new RuntimeException("卡号不存在");
}
//2.2验证password是否正确
if(!(password.equals(account.getPassword()))){
throw new RuntimeException("密码错误");
}
//2.3验证余额是否充足
if(account.getBalance()<money){
throw new RuntimeException("余额不足");
}
//2.4验证toID是否存在
Account account1 = accountDao.select(toID);
if(account1==null){
throw new RuntimeException("对方卡不存在");
}
//2.4减少fromID的余额
account.setBalance(account.getBalance()-money);
accountDao.update(account);
//2.5增加toID的余额
account1.setBalance(account1.getBalance()+money);
accountDao.update(account1);
System.out.println("转账成功");
conn.commit();//手动提交事务
}catch (RuntimeException | SQLException e){
System.out.println("转账失败");
//出现异常回滚事务
conn.rollback();//手动回滚事务
e.printStackTrace();
}
}
}
结果发现加了事务结果还是出问题,原因在于connection不唯一,服务层调用了多个connection
解决方法
为了解决线程中connection对象不同步的问题,可以将connection对象通过service传递给各个DAO方法
传递的问题
如果使用传递connection容易造成接口污染(badsmell)
定义接口是为了更容易更换实现 而将connection定义在接口中,会造成污染当前接口
解决方法 threadlocal
可以将整个线程中(单线程),存储一个共享值
线程用于一个类似Map的属性,键值对结构为<threadlocal,值>
ThreadLocal
一个线程共享同一个ThreadLocal,在整个流程中任意一环节可以存值或者取值
修改后的DButils
package account;
import JDBC.DBUtils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DButils {
private static final Properties PROPERTIES=new Properties();
private static final ThreadLocal<Connection> THREAD_LOCAL=new ThreadLocal<>();
static {
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
try {
PROPERTIES.load(is);
Class.forName(PROPERTIES.getProperty("driver"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getconnection(){
Connection conn=THREAD_LOCAL.get();//获取线程中存储的connection对象
try {
if(conn==null){//如果连接对象为空则创建连接
conn= DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("username"),PROPERTIES.getProperty("password"));
THREAD_LOCAL.set(conn);//把连接存在当前线程共享中
}
return conn;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
public static void closeall(Connection conn, PreparedStatement pst, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(pst!=null){
try {
pst.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
所以对Dao层里面的关闭连接也要做对应的修改,Service层操作的connection对象应该是同一个,所以在Dao层不应该关闭connection对象,而应该在Service层事务处理完后在关闭connection连接
AccountDaoImpl类
package account;
import JDBC.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AccountDaoImpl {
public int insert(Account account){
return 0;
}
public int delete(String cardID){
return 0;
}
public int update(Account account){
int count;
Connection conn=null;
PreparedStatement pst=null;
conn=DBUtils.getconnection();
String sql="update account set password=?,name=?,balance=? where cardID=?";
try {
pst=conn.prepareStatement(sql);
pst.setString(1,account.getPassword());
pst.setString(2,account.getName());
pst.setDouble(3,account.getBalance());
pst.setString(4,account.getCardID());
count=pst.executeUpdate();
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(null,pst,null);
}
return 0;
}
public Account select(String cardID){
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
Account account=null;
conn= DBUtils.getconnection();
String sql="select * from account where cardID=?";
try {
pst=conn.prepareStatement(sql);
pst.setString(1,cardID);
rs = pst.executeQuery();
if(rs.next()){
String id = rs.getString("cardID");
String password = rs.getString("password");
String name = rs.getString("name");
double balance = rs.getDouble("balance");
account=new Account(id,password,name,balance);
}
return account;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeall(null,pst,rs);
}
return null;
}
}
AccountserviceImpl 类
package account;
import JDBC.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
public class AccountserviceImpl {
public void transfer(String fromID,String password,String toID,double money) throws SQLException {
//1.接收传递参数 转账的卡号 密码 被转的卡号 转账的金额
//2.组织完善业务功能
AccountDaoImpl accountDao = new AccountDaoImpl();
Connection conn=null;
try {
//建立一个数据库连接
conn= DBUtils.getconnection();
//开启事务 并且关闭事务的自动提交
conn.setAutoCommit(false);
//2.1验证fromID是否存在
Account account = accountDao.select(fromID);
if(account==null){
throw new RuntimeException("卡号不存在");
}
//2.2验证password是否正确
if(!(password.equals(account.getPassword()))){
throw new RuntimeException("密码错误");
}
//2.3验证余额是否充足
if(account.getBalance()<money){
throw new RuntimeException("余额不足");
}
//2.4验证toID是否存在
Account account1 = accountDao.select(toID);
if(account1==null){
throw new RuntimeException("对方卡不存在");
}
//2.4减少fromID的余额
account.setBalance(account.getBalance()-money);
accountDao.update(account);
//2.5增加toID的余额
account1.setBalance(account1.getBalance()+money);
accountDao.update(account1);
System.out.println("转账成功");
conn.commit();//手动提交事务
}catch (RuntimeException | SQLException e){
System.out.println("转账失败");
//出现异常回滚事务
conn.rollback();//手动回滚事务
e.printStackTrace();
}finally {
DBUtils.closeall(conn,null,null);
}
}
}
对事务封装的DBUtils
package account;
import JDBC.DBUtils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DButils {
private static final Properties PROPERTIES=new Properties();
private static final ThreadLocal<Connection> THREAD_LOCAL=new ThreadLocal<>();
static {
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
try {
PROPERTIES.load(is);
Class.forName(PROPERTIES.getProperty("driver"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getconnection(){
Connection conn=THREAD_LOCAL.get();//获取线程中存储的connection对象
try {
if(conn==null){//如果连接对象为空则创建连接
conn= DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("username"),PROPERTIES.getProperty("password"));
THREAD_LOCAL.set(conn);//把连接存在当前线程共享中
}
return conn;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//事务的开启
public static void begin()
{
Connection conn=null;
try {
conn=getconnection();
conn.setAutoCommit(false);
}catch (SQLException e)
{
e.printStackTrace();
}
}
//提交事务
public static void commit()
{
Connection conn=null;
try {
conn=getconnection();
conn.commit();
}catch (SQLException e)
{
e.printStackTrace();
}finally {
DBUtils.closeall(conn,null,null);
}
}
//回滚事务
public static void rollback()
{
Connection conn=null;
try {
conn=getconnection();
conn.rollback();
}catch (SQLException e)
{
e.printStackTrace();
}finally {
DBUtils.closeall(conn,null,null);
}
}
public static void closeall(Connection conn, PreparedStatement pst, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(pst!=null){
try {
pst.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
THREAD_LOCAL.remove();//关闭连接后移除已关闭的connection对象
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
三层架构
什么是三层架构
表示层:
命名:XXXView
职责:收集用户的数据和需求,展示数据
业务逻辑层
命名:XXXServiceImpl
职责:数据加工处理,调用DAO完成业务实现,控制事务
数据访问层
命名:XXXDaoImpl
职责:向业务层提供数据,将业务层加工后的数据同步到数据库
三层架构项目搭建
utils 存放工具类 DBUtils
entity 存放实体类
dao 存放DAO接口
Impl存放DAO接口的实现类
service 存放service接口
Impl存放service接口的实现类
view 存放程序的启动类
三层架构在idea中的截图
lib是存放jar包的直接在整个工程下建立,db.properties是在src下建立的,其他包如图所示
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db3?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username=root
password=123456
PersonDao 接口
package com.blb.dao;
import com.blb.entity.Person;
import java.util.List;
public interface PersonDao {
public int insert(Person person);
public int update(Person person);
public int delete(int id);
public Person select(int id);
public List<Person> selectAll();
}
PersonDaoImpl类
package com.blb.dao.Impl;
import com.blb.dao.PersonDao;
import com.blb.entity.Person;
import com.blb.utils.DButils;
import com.blb.utils.Dateutils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class PersonDaoImpl implements PersonDao {
@Override
public int insert(Person person) {
Connection conn=null;
PreparedStatement pst=null;
String sql="insert into person(name,age,borndate,email,address) values(?,?,?,?,?);";
conn=DButils.getConnection();
try {
pst= conn.prepareStatement(sql);
pst.setString(1,person.getName());
pst.setInt(2,person.getAge());
pst.setDate(3, Dateutils.UtiltoSql(person.getBorndate()));
pst.setString(4,person.getEmail());
pst.setString(5,person.getAddress());
int i = pst.executeUpdate();
return i;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,null);
}
return 0;
}
@Override
public int update(Person person) {
Connection conn=null;
PreparedStatement pst=null;
String sql="update person set name=?,age=?,borndate=?,email=?,address=? where id=?;";
conn=DButils.getConnection();
try {
pst= conn.prepareStatement(sql);
pst.setString(1,person.getName());
pst.setInt(2,person.getAge());
pst.setDate(3, Dateutils.UtiltoSql(person.getBorndate()));
pst.setString(4,person.getEmail());
pst.setString(5,person.getAddress());
pst.setInt(6,person.getId());
int i = pst.executeUpdate();
return i;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,null);
}
return 0;
}
@Override
public int delete(int id) {
Connection conn=null;
PreparedStatement pst=null;
String sql="delete from person where id=?;";
conn=DButils.getConnection();
try {
pst= conn.prepareStatement(sql);
pst.setInt(1,id);
int i = pst.executeUpdate();
return i;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,null);
}
return 0;
}
@Override
public Person select(int id) {
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
String sql="select * from person where id=?";
Person person=null;
conn=DButils.getConnection();
try {
pst= conn.prepareStatement(sql);
pst.setInt(1,id);
rs= pst.executeQuery();
if(rs.next()){
int id1 = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
String email = rs.getString("email");
String address = rs.getString("address");
Date date = rs.getDate("borndate");
person=new Person(id1,name,age,date,email,address);
}
return person;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,rs);
}
return null;
}
@Override
public List<Person> selectAll() {
List<Person> arr=new ArrayList<>();
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
String sql="select * from person ";
Person person=null;
conn=DButils.getConnection();
try {
pst= conn.prepareStatement(sql);
rs= pst.executeQuery();
while (rs.next()){
int id1 = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
String email = rs.getString("email");
String address = rs.getString("address");
Date date = rs.getDate("borndate");
person=new Person(id1,name,age,date,email,address);
arr.add(person);
}
return arr;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,rs);
}
return null;
}
}
PersonService接口
package com.blb.service;
import com.blb.entity.Person;
import java.util.List;
public interface PersonService {
public int insert(Person person);
public int update(Person person);
public int delete(int id);
public Person select(int id);
public List<Person> selectAll();
}
PersonServiceImpl类
package com.blb.service.Impl;
import com.blb.dao.Impl.PersonDaoImpl;
import com.blb.dao.PersonDao;
import com.blb.entity.Person;
import com.blb.service.PersonService;
import java.util.List;
public class PersonServiceImpl implements PersonService {
private PersonDao pd=new PersonDaoImpl();
@Override
public int insert(Person person) {
int insert = pd.insert(person);
return insert;
}
@Override
public int update(Person person) {
int update = pd.update(person);
return update;
}
@Override
public int delete(int id) {
int delete = pd.delete(id);
return delete;
}
@Override
public Person select(int id) {
Person person = pd.select(id);
return person;
}
@Override
public List<Person> selectAll() {
List<Person> people = pd.selectAll();
return people;
}
}
可以看到Service层操作Dao层,方法都是一样的,Dao层操作数据库,但是代码还是很长很冗余
所以对数据库的增删改查操作进行抽取封装DaoUtils
DaoUtils
package com.blb.utils;
import com.blb.advanced.RowMapper;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Daoutils<T>{
/**
* 公共处理增删改的方法
* @param sql 执行的sql语句
* @param args 参数列表
* @return
*/
public int commonsUpdate(String sql,Object...args){
Connection conn=null;
PreparedStatement pst=null;
conn = DButils.getConnection();
try {
pst=conn.prepareStatement(sql);
for(int i=0;i<args.length;i++){
pst.setObject(i+1,args[i]);
}
int i = pst.executeUpdate();
return i;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,null);
}
return 0;
}
public List<T> commonsSelect(String sql, RowMapper<T> rowMapper,Object...args)
{
List<T> arr=new ArrayList<>();
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
conn=DButils.getConnection();
pst=conn.prepareStatement(sql);
if(args!=null){//注意要判断非空否则查询所有的时候会报错误
for(int i=0;i<args.length;i++)
{
pst.setObject(i+1,args[i]);
}
}
rs = pst.executeQuery();
while (rs.next()){
//根据查询到的结果完成orm
T t=rowMapper.getRow(rs);
arr.add(t);
}
return arr;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DButils.closeall(null,pst,rs);
}
return null;
}
}
在建一个包用于实现查询里面的orm映射,并且使用泛型这样可以供所有的使用
RowMapper 接口
package com.blb.advanced;
import java.sql.ResultSet;
public interface RowMapper<T> {
public T getRow(ResultSet rs);
}
PersonRowMapper 实现类
package com.blb.advanced.Impl;
import com.blb.advanced.RowMapper;
import com.blb.entity.Person;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PersonRowMapper implements RowMapper<Person> {
@Override
public Person getRow(ResultSet rs) {
Person person=null;
int id1 = 0;
try {
id1 = rs.getInt("id");
int age = rs.getInt("age");
String name = rs.getString("name");
String email = rs.getString("email");
String address = rs.getString("address");
Date date = rs.getDate("borndate");
person=new Person(id1,name,age,date,email,address);
return person;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
修改完后的PersonDaoImpl
package com.blb.dao.Impl;
import com.blb.advanced.Impl.PersonRowMapper;
import com.blb.dao.PersonDao;
import com.blb.entity.Person;
import com.blb.utils.Daoutils;
import java.util.List;
public class PersonDaoImpl implements PersonDao {
private Daoutils<Person> daoutils=new Daoutils<>();
@Override
public int insert(Person person) {
String sql="insert into person(name,age,borndate,email,address) values(?,?,?,?,?);";
Object args[]={person.getName(),person.getAge(),person.getBorndate(),person.getEmail(),person.getAddress()};
return daoutils.commonsUpdate(sql,args);
}
@Override
public int update(Person person) {
String sql="update person set name=?,age=?,borndate=?,email=?,address=? where id=?;";
Object args[]={person.getName(),person.getAge(),person.getBorndate(),person.getEmail(),person.getAddress(),person.getId()};
return daoutils.commonsUpdate(sql,args);
}
@Override
public int delete(int id) {
String sql="delete from person where id=?;";
return daoutils.commonsUpdate(sql,id);
}
@Override
public Person select(int id) {
String sql="select * from person where id=?";
List<Person> people = daoutils.commonsSelect(sql, new PersonRowMapper(), id);
if(!people.isEmpty()){
return people.get(0);
}
return null;
}
@Override
public List<Person> selectAll() {
String sql="select * from person ";
List<Person> people = daoutils.commonsSelect(sql, new PersonRowMapper(),null);
if(!people.isEmpty()){
return people;
}
return null;
}
}
Druid连接池
在程序初始化时,预先创建指定数量的数据库连接对象存储在池中,当需要连接数据库时,从连接池中取出现有连接,使用完毕后,也不会进行关闭,而是放回到连接池中,实现复用,节省资源
连接池的配置文件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db3?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username=root
password=123456
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位
maxWait=5000
DButils
package com.blb.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DButils {
//声明连接池对象
private static DruidDataSource ds;
private static final ThreadLocal<Connection> THREAD_LOCAL=new ThreadLocal<>();
static {
//实例化配置对象
Properties properties=new Properties();
InputStream inputStream= DButils.class.getResourceAsStream("/db.properties");
try {
properties.load(inputStream);
ds=(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection()
{
Connection conn=THREAD_LOCAL.get();
try {
if(conn == null){
conn=ds.getConnection();
THREAD_LOCAL.set(conn);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void begin(){
Connection conn=null;
try {
conn=getConnection();
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void commit(){
Connection conn=null;
try {
conn=getConnection();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closall(conn,null,null);
}
}
public static void rollback()
{
Connection conn=null;
try {
conn=getConnection();
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closall(conn,null,null);
}
}
public static void closall(Connection conn, PreparedStatement pst, ResultSet rs){
try {
if(rs!=null){
rs.close();
if(pst!=null){
pst.close();
}
if(conn!=null){
conn.close();
THREAD_LOCAL.remove();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//返回一个数据源
public static DataSource getDataSource(){
return ds;
}
}
测试连接池
package com.blb.test;
import com.blb.utils.DButils;
import java.sql.Connection;
import java.sql.SQLException;
public class pooltest {
public static void main(String[] args) {
for(int i=0;i<15;i++){
Connection conn= DButils.getConnection();
System.out.println(conn);
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注意连接池的关闭连接并不是关闭而是归还给连接池
Apache的DbUtils使用
Commons DbUtils 是Apache组织提供的一个对JDBC进行简单的封装的开源工具类库,使用它能简化JDBC应用程序开发
简介
DbUtils是java编程中数据库操作使用小工具,小巧,简单,实用
对于数据表的查询操作,可以把结果转换为List,Array,set等集合,便于操作
对于数据表的DML操作,也变得很简单(只需要写sql语句)
DbUtils主要包含
ResultSetHandler接口:转换类接口
BeanHandler类:实现类,把一条记录转化成对象
BeanListHandler类:实现类,把多条记录转化成List集合
ScalarHandler类:实现类,适合获取一行一列的数据
QueryRunner 类执行sql语句的类
增,删,改:update()
查询 :query()
DButils
主要多加了一个方法返回数据源的方法,因为queryRunner需要一个数据源作为参数创建对象
package com.blb.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DButils {
//声明连接池对象
private static DruidDataSource ds;
static {
//实例化配置对象
Properties properties=new Properties();
InputStream inputStream= DButils.class.getResourceAsStream("/db.properties");
try {
properties.load(inputStream);
ds=(DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection()
{
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//返回一个数据源
public static DataSource getDataSource(){
return ds;
}
}
person实体类
package com.blb.entity;
import java.util.Date;
public class Person {
private int id;
private String name;
private int age;
private Date borndate;
private String email;
private String address;
public Person() {
}
public Person(String name, int age, Date borndate, String email, String address) {
this.name = name;
this.age = age;
this.borndate = borndate;
this.email = email;
this.address = address;
}
public Person(int id, String name, int age, Date borndate, String email, String address) {
this.id = id;
this.name = name;
this.age = age;
this.borndate = borndate;
this.email = email;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBorndate() {
return borndate;
}
public void setBorndate(Date borndate) {
this.borndate = borndate;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", borndate=" + borndate +
", email='" + email + '\'' +
", address='" + address + '\'' +
'}';
}
}
PersonDao 接口
package com.blb.dao;
import com.blb.entity.Person;
import java.util.List;
public interface PersonDao {
public int insert(Person person);
public int update(Person person);
public int delete(int id);
public Person select(int id);
public List<Person> selectAll();
public long count();
}
PersonDaoImpl类
package com.blb.dao.Impl;
import com.blb.dao.PersonDao;
import com.blb.entity.Person;
import com.blb.utils.DButils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.SQLException;
import java.util.List;
public class PersonDaoImpl implements PersonDao {
//创建一个QueryRunner对象,并传递一个数据源对象
QueryRunner queryRunner=new QueryRunner(DButils.getDataSource());
@Override
public int insert(Person person) {
String sql="insert into person(name,age,borndate,email,address) values(?,?,?,?,?);";
Object args[]={person.getName(),person.getAge(),person.getBorndate(),person.getEmail(),person.getAddress()};
try {
return queryRunner.update(sql,args);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int update(Person person) {
String sql="update person set name=?,age=?,borndate=?,email=?,address=? where id=?;";
Object args[]={person.getName(),person.getAge(),person.getBorndate(),person.getEmail(),person.getAddress(),person.getId()};
try {
return queryRunner.update(sql,args);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int delete(int id) {
String sql="delete from person where id=?;";
try {
return queryRunner.update(sql,id);
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public Person select(int id) {
String sql="select * from person where id=?";
try {
//把查询到的记录封装成指定对象
Person query = queryRunner.query(sql, new BeanHandler<Person>(Person.class), id);
return query;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public List<Person> selectAll() {
String sql="select * from person ";
try {
List<Person> query = queryRunner.query(sql, new BeanListHandler<Person>(Person.class));
return query;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//查询总人数
@Override
public long count() {
String sql="select count(*) from person ;";
try {
Long query = queryRunner.query(sql, new ScalarHandler<>());
return query;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
}