版权声明:《==study hard and make progress every day==》 https://blog.csdn.net/qq_38225558/article/details/82871895
表t_account:
表t_user:
功能实现类
/**
* 实现类
* @author 郑清
*/
public class UserDaoImpl implements IUserDao {
@Override
public void add(User user) {
// TODO Auto-generated method stub
Connection connection = null;
PreparedStatement ps = null;
try {
//1.加载驱动
//2.获取连接:与数据库建立连接
connection = JDBCUtil.instance.getConnection();
//3.使用预编译对象 PreparedStatement实现添加,特点:创建 PreparedStatement对象时,就指定了sql语句发送到dbms进行编译
//4.执行sql语句 (注意:当3.中编译语句执行的时候不需要传sql dbms会直接运行编译后的sql语句)
String sql = "insert into t_user(username,password) values (?,?);";// ? ==> 占位符
ps = connection.prepareStatement(sql);
ps.setString(1, user.getUsername());//占位符?从1开始
ps.setString(2, user.getPassword());
ps.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.释放资源 (注意:关闭资源顺序 先打开后关闭)
JDBCUtil.instance.close(connection, ps, null);
}
}
@Override
public void delete(int id) {
// TODO Auto-generated method stub
Connection connection = null;
PreparedStatement ps = null;
try {
//1.加载驱动
//2.获取连接:与数据库建立连接
connection = JDBCUtil.instance.getConnection();
//3.使用预编译对象 PreparedStatement实现删除,特点:创建 PreparedStatement对象时,就指定了sql语句发送到dbms进行编译
//4.执行sql语句 (注意:当3.中编译语句执行的时候不需要传sql dbms会直接运行编译后的sql语句)
String sql = "delete from t_user where id = ? ;";// ? ==> 占位符
ps = connection.prepareStatement(sql);
ps.setInt(1, id);//占位符?从1开始
ps.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.释放资源 (注意:关闭资源顺序 先打开后关闭)
JDBCUtil.instance.close(connection, ps, null);
}
}
@Override
public void update(User user) {
// TODO Auto-generated method stub
Connection connection = null;
PreparedStatement ps = null;
String sql = "update t_user set username = ? , password = ? where id = ? ;";// ? ==> 占位符
try {
//1.加载驱动
//2.获取连接:与数据库建立连接
connection = JDBCUtil.instance.getConnection();
//3.使用预编译对象 PreparedStatement实现更新,特点:创建 PreparedStatement对象时,就指定了sql语句发送到dbms进行编译
//4.执行sql语句 (注意:当3.中编译语句执行的时候不需要传sql dbms会直接运行编译后的sql语句)
ps = connection.prepareStatement(sql);
ps.setString(1,user.getUsername());//占位符?从1开始
ps.setString(2,user.getPassword());
ps.setInt(3,user.getId());
ps.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.释放资源 (注意:关闭资源顺序 先打开后关闭)
JDBCUtil.instance.close(connection, ps, null);
}
}
@Override
public User queryOne(int id) {
// TODO Auto-generated method stub
Connection connection = null;
PreparedStatement ps = null;
String sql = "select * from t_user where id = ? ;";
ResultSet rs = null;
User user = null;
try {
//1.加载驱动
//2.获取连接:与数据库建立连接
connection = JDBCUtil.instance.getConnection();
//3.使用预编译对象 PreparedStatement实现查找,特点:创建 PreparedStatement对象时,就指定了sql语句发送到dbms进行编译
//4.执行sql语句 (注意:当3.中编译语句执行的时候不需要传sql dbms会直接运行编译后的sql语句)
ps = connection.prepareStatement(sql);
ps.setInt(1, id);//占位符?从1开始
rs = ps.executeQuery();
while(rs.next()) {
user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.释放资源 (注意:关闭资源顺序 先打开后关闭)
JDBCUtil.instance.close(connection, ps, rs);
}
return user;
}
@Override
public List<User> queryAll() {
// TODO Auto-generated method stub
//1.加载驱动
//2.获取连接:与数据库建立连接
Connection connection = JDBCUtil.instance.getConnection();
PreparedStatement ps = null;
String sql = "select * from t_user;";
ResultSet rs = null;
List<User> userList = new ArrayList<>();
try {
//3.使用预编译对象 PreparedStatement实现查找,特点:创建 PreparedStatement对象时,就指定了sql语句发送到dbms进行编译
//4.执行sql语句 (注意:当3.中编译语句执行的时候不需要传sql dbms会直接运行编译后的sql语句)
ps = connection.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()){
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
userList.add(user);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//5.释放资源 (注意:关闭资源顺序 先打开后关闭)
JDBCUtil.instance.close(connection, ps, rs);
}
return userList;
}
//Statement方式 username+password
public User login1(String username,String password) {
Connection connection = JDBCUtil.instance.getConnection();
Statement statement = null;
ResultSet rs = null;
User user = null;
try {
String sql = "select * from t_user where username = '"+username+"' and password = '"+password+"'";
System.out.println(sql);
statement = connection.createStatement();
rs = statement.executeQuery(sql);
while(rs.next()){
user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.instance.close(connection, statement, rs);
}
return user;
}
//Statement方式 username
public User login2(String name) {
Connection connection = JDBCUtil.instance.getConnection();
Statement statement = null;
ResultSet rs = null;
User user = null;
try {
String sql = "select * from t_user where username = '"+name+"';";
System.out.println(sql);
statement = connection.createStatement();
rs = statement.executeQuery(sql);
while(rs.next()){
user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.instance.close(connection, statement, rs);
}
return user;
}
//Statement方式 username+password ==> 验证sql注入问题【用户传入的数据,决定了sql拼接的结果】
public User login3(String username,String password) {
Connection conn = JDBCUtil.instance.getConnection();
Statement statement = null;
ResultSet rs = null;
User user = null;
try {
String sql = "select * from t_user where username = '"+username+"'and password = '"+password+";";
System.out.println(sql);
statement = conn.createStatement();
rs = statement.executeQuery(sql);
while(rs.next()){//rs拿出了表中的所有数据
user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.instance.close(conn, statement, rs);
}
return user;
}
//PreparedStatement方式 username+password ==> 解决sql注入问题【用户传入的数据,决定了sql拼接的结果】
public User login4(String username,String password) {
Connection conn = JDBCUtil.instance.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
String sql = "select * from t_user where username = ? and password = ? ;";
System.out.println(sql);
ps = conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);//'154562' or 1=1 or
rs = ps.executeQuery();
while(rs.next()){//rs拿出了表中的所有数据
user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.instance.close(conn, ps, rs);
}
return user;
}
//事务问题,同生共死 (即一组操作 同时生 同时死)
/*
* 1.InnoDB:自动提交事物:都可以正常的提交事务,该减减 该加加
* 2.InnoDB:自动提交事物:
* 添加了异常代码:发现,减的减了,但是因为异常,加的没有执行
* 3.InnoDB:设置手动提交事物:
* 1.不添加异常:都正常执行了
* 2.添加异常:没减也没加
* 4.InnoDB:设置手动提交事物:解释了什么 叫做一组操作,引出了必须要回滚事务
* 5.数据库的存储引擎,InnoDB支持事务【如果支持事务控制数据库必须是InnoDB】 MyISAM不支持事务
* MyISAM验证不支持事务:
* 1.把conn.setAutoCommit(false);//手动提交
* 2.执行过程中设计了异常
* 3.事务都是手动提交的,发现出现异常:肯定没有提交,
* 发现,数据库中的数据已经变化了,而且回滚也没有效果
*/
public void transaction(){
Connection connection = JDBCUtil.instance.getConnection();
PreparedStatement ps = null;
try {
connection.setAutoCommit(false);//设置手动提交
String sql = "update t_account set money = money-100 where username = '大熊';";
ps = connection.prepareStatement(sql);
ps.executeUpdate(sql);
System.out.println(1/0);//此处会出现异常 作用:测试手动提交时遇到异常无法执行下一步的操作时进行事务的数据回滚
sql = "update t_account set money = money+100 where username = '包租公';";
ps.executeUpdate(sql);
connection.commit();//提交事务
} catch (Exception e) {
try {
connection.rollback();//如果操作失败 比如遇到异常则进行事务的数据回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JDBCUtil.instance.close(connection,ps, null);
}
}
//方式一:Statement 向用户表t_user中添加一个用户 【拿到这个用户的主键】 把这个主键添加到t_account表
public void getPrimaryKeyByStatement(){
Connection conn = JDBCUtil.instance.getConnection();
Statement statement = null;
ResultSet rs = null;
try {
String sql = "insert into t_user (username,password) values ('哆啦A梦','123456');";
statement = conn.createStatement();
//返回操作了多少条数据
int rownum = statement.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);//RETURN_GENERATED_KEYS:该常量指示生成的键应该可用于获取。
System.out.println(rownum);//修改的行数
//Statement拿到主键的方式:
rs = statement.getGeneratedKeys();//getGeneratedKeys():获取由于执行此 Statement 对象而创建的所有自动生成的键。
while(rs.next()) {
long key = rs.getInt(1);
System.out.println(key);
sql = "insert into t_account (id,username) values ("+key+",'t_user中拿到的id');";
}
statement.executeUpdate(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtil.instance.close(conn, statement, rs);
}
}
//方式二:PreparedStatement 向用户表t_user中添加一个用户 【拿到这个用户的主键】 把这个主键添加到t_account表
public void getPrimaryKeyByPreparedStatement(){
Connection conn = JDBCUtil.instance.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "insert into t_user (username,password) values (?,?);";
ps = conn.prepareStatement(sql,ps.RETURN_GENERATED_KEYS);//RETURN_GENERATED_KEYS:该常量指示生成的键应该可用于获取
ps.setString(1, "奥特曼");
ps.setString(2, "123456");
int rownum = ps.executeUpdate();
System.out.println(rownum);//修改的行数
//拿到主键
rs = ps.getGeneratedKeys();//getGeneratedKeys():获取由于执行此 Statement 对象而创建的所有自动生成的键
while(rs.next()) {
long key = rs.getInt(1);
System.out.println(key);
sql = "insert into t_account (id,username) values ("+key+",'t_user中拿到的id');";
}
ps.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.instance.close(conn, ps, rs);
}
}
}
接口类:
/**
* 接口类
* @author 郑清
*/
public interface IUserDao {
void add(User user);
void delete(int id);
void update(User user);
User queryOne(int id);
List<User> queryAll();
}
测试类:
/**
* 使用Junit4测试 数据库的增删改查
* 测试PreparedStatement的安全性
* 测试事务
* 获取主键
* @author 郑清
*/
public class UserDaoTest {
UserDaoImpl userDao = new UserDaoImpl();
@Test
public void testAdd() {
User user = new User();
user.setUsername("小猪佩奇");
user.setPassword("123456");
userDao.add(user);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(13);
user.setUsername("大熊");
user.setPassword("488646");
userDao.update(user);
}
@Test
public void testDelete(){
userDao.delete(16);
}
@Test
public void testQueryOne(){
User user = userDao.queryOne(3);
System.out.println(user);
}
@Test
public void testQueryAll(){
List<User> users = userDao.queryAll();
for (User user : users) {
System.out.println(user);
}
}
//===============testLogin3和testLogin4测试PreparedStatement的安全性=============================
@Test
public void testLogin1() {
String username = "李四";
String password = "123456";
User user = userDao.login1(username, password);
if(user==null){
System.out.println("登陆失败:用户名或者密码错误!!!");
}else{
System.out.println("登陆成功!!!");
}
}
@Test//注意:如果只通过账户名查询对象,除了验证对象 必须验证密码是否正确
public void testLogin2() {
String username = "李四2";
String password = "123456";
//从数据库里面根据账户查询数据,返回一个对象
User user = userDao.login2(username);
//必须堆账户及密码验证,否则仅验证查询的,如果密码错了也是可以登陆的
if(user==null||!user.getPassword().equals(password)){
System.out.println("登陆失败:用户名或者密码错误!!!");
}else{
System.out.println("登陆成功!!!");
}
}
@Test//Statement:存在sql注入的问题
public void testLogin3() {
String username = "李四";
String password = "645456' or 1=1 or''";
User user = userDao.login3(username, password);
if(user==null){
System.out.println("登陆失败:用户名或者密码错误!!!");
}else{
System.out.println("登陆成功!!!");
}
}
@Test//使用preparedStatement解决sql注入的问题
public void testLogin4() {
String username = "李四";
String password = "645456' or 1=1 or''";
User user = userDao.login4(username, password);
if(user==null){
System.out.println("登陆失败:用户名或者密码错误!!!");
}else{
System.out.println("登陆成功!!!");
}
}
@Test//测试事务问题,同生共死 (即一组操作 同时生 同时死)
public void testTransaction () {
userDao.transaction();
}
@Test//方式一:Statement
public void testGetPrimaryKeyByStatement(){
userDao.getPrimaryKeyByStatement();
}
@Test//方式二:PreparedStatement
public void testGetPrimaryKeyByPreparedStatement(){
userDao.getPrimaryKeyByPreparedStatement();
}
}
工具类:
/**
* 工具类:
* 抽取公共部分,做单例模式
* DBCP方式实现连接池、配置连接池 ==> 获得连接对象
* @author 郑清
*/
public enum JDBCUtil {
instance;
private static Properties p = new Properties();
// private static BasicDataSource ds = new BasicDataSource();//获得连接池对象 方式1
private static DataSource ds = null;//获取连接池对象 方式2
//加载驱动
static {//当用到该工具类的时候,会自动加载驱动
try {
//读取配置文件db.properties
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
//加载驱动
/*
//获得连接池对象 方式1
ds.setDriverClassName(p.getProperty("driverClassName"));
ds.setUsername(p.getProperty("username"));
ds.setPassword(p.getProperty("password"));
ds.setUrl(p.getProperty("url"));
*/
//连接池可以配置,初始化的连接数量,最大连接数量,最小连接数量等等
//获取连接池对象 方式2 [注意:配置文件(db.properties)里 驱动,url 数据库用户名、密码 必须规范!!]
ds = BasicDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接:与数据库建立连接
public Connection getConnection(){//没有static:应该通过对象(枚举对象instance)调用该方法
try {
return ds.getConnection();//通过连接池对象ds获取连接
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//释放资源 (注意:关闭资源顺序 先打开后关闭)
public void close(Connection connection,Statement statement,ResultSet rs){
try {
if(rs!=null)rs.close();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally{
try {
if(statement!=null)statement.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null)connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
实体类:
/**
* 用户账号实体类
* @author 郑清
*/
public class User {
private int id;
private String username;
private String password;
public User() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 "User [id=" + id + ", username=" + username + ", password=" + password + "]";
}
}