目录
- PreparedStatement 查询
 - 1.sql注入
 - 2.Statement分析 (面试题)
 - 3.PreparedStatement (面试题)
 
- 登录功能的完善
 - 事务
 - 链接池
 - 概念
 - 实现
 - DBCP连接池实现
 - 第一种配置方式
 - 第二种配置方式
 
- 返回主键
 - BaseDao的抽取
 
PreparedStatement 查询
1.sql注入
就是在sql的字符串拼接的时候,加入了特定的条件判断,
如:SELECT * FROM student where name=’ 小坤坤255255 ’ OR 1=1
代码
public class StudentDaoImpl  implements IStudentDao{
	//Statement的写法
	@Override
	public Student login(String name, String Password) {
		//通过工具类获取连接
		Connection conn = JDBCUtil.Instance().getconn();
		Statement State =null;
		ResultSet rs=null;
		Student student = new Student();
		try {
			 State = conn.createStatement();
			  rs = State.executeQuery("select * from student where name='"+name+"'and password ='"+Password+"'");
		      while (rs.next()) {
		    	  student.setId(rs.getInt("id"));
		    	  student.setName(rs.getString("name"));
		    	  student.setPassword(rs.getString("password"));
			} 
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.Instance().close(rs, State, conn);
		}
		return student;
	}
}
 
public class JDBCTest {
	@Test
	public void testName() throws Exception {
		StudentDaoImpl studentDaoImpl = new  StudentDaoImpl();
		//正常的代码
//		Student stu = studentDaoImpl.login("网通", "123");
		//sql注入的代码
		Student stu = studentDaoImpl.login("网通", "123' or '1=1");
		System.out.println(stu);
		if(stu.getName()!=null){
			System.out.println("账号存在登录成功");
		}else{
			System.out.println("账号不存在  ..登录失败");
		}
	}
}
 
2.Statement分析 (面试题)
1.通过上面sql注入的案例我们发现 Statement 它可能会导致sql注入的问题
 2.通过这几天的sql的书写我发现 Statement 拼接sql相当复杂,稍微有一点点差错就会导致sql语句有问题
解决方法:PreparedStatement
3.PreparedStatement (面试题)
PreparedStatement 很好的解决了Statement的问题
 1.不用担心注入问题(双引号之内看成一个整体的字符串而不是两个字符串和一个关键字),
 2.sql语句不用复杂拼接,
 3.会预处理sql语句,执行速度也更快
代码:
 StudentDaoImpl
	//PreparedStatement写法
	@Override
	public Student login(String name, String Password) {
		 Connection conn = JDBCUtil2.Instance().getconn();
		 PreparedStatement ps=null;
		 ResultSet rs =null;
		 Student student = new Student();
		 try {
			 ps= conn.prepareStatement("select * from student  where name=? and password=?");
			 ps.setString(1, name);
			 ps.setString(2, Password);
			 rs = ps.executeQuery();
			 while(rs.next()){
				 student.setId(rs.getInt("id"));
				 student.setName(rs.getString("name"));
				 student.setPassword(rs.getString("password"));
			 }
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil2.Instance().close(rs, ps, conn);
		}
	return student;
	}
 
JDBCTest
	@Test
	public void testName() throws Exception {
		StudentDaoImpl studentDaoImpl = new  StudentDaoImpl();
		//正常的代码
//		Student stu = studentDaoImpl.login("网通", "123");
		//sql注入的代码
		Student stu = studentDaoImpl.login("网通", "123' or '1=1");
		System.out.println(stu);
		if(stu.getName()!=null){
			System.out.println("账号存在登录成功");
		}else{
			System.out.println("账号不存在  ..登录失败");
		}
	}
 
问题:PreparedStatement和Statement 不是同一个类为什么关资源的时候可以传PreparedStatement
 因为 PreparedStatement 继承了 Statement,(多态)
PreparedStatement :
  // 预处理 这时候就会把sql发送到数据库了,只是这时还不会执行sql
  select * from student  where name=? and password=? 		//变量位置使用?先占住,(这时已经发了sql语句了)
  ps= conn.prepareStatement("select * from student  where name=? and password=?");
  // 把?替换成对应的值
  ps.setString(1, name);
  ps.setString(2, Password);
  // 执行sql  这时的执行就是一个执行命令,不会发sql语句(前面已发)
  rs = ps.executeQuery();
 
Statement:
  //创建 Statement 对象 
  State = conn.createStatement();
  // 发送并执行sql 
  rs = State.executeQuery("select * from student where name='"+name+"'and password ='"+Password+"'");
 
PreparedStatement 是 Statement 子类,速度比Statement 快,能避免sql 注入,可以不用拼接sql语句
登录功能的完善
StudentDaoImpl
	@Override
	public Student QueryByUsername(String name) {
		Connection conn = JDBCUtil2.Instance().getconn();
		PreparedStatement ps = null;
		ResultSet rs = null;
		Student student = new Student();
		try {
			ps = conn.prepareStatement("select * from student where name=?");
			ps.setString(1, name);
			rs = ps.executeQuery();
			while (rs.next()) {
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setPassword(rs.getString("password"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil2.Instance().close(rs, ps, conn);
		}
		return student;
	}
 
JDBCTest
	// 登录的第二种实现方式
	@Test
	public void login() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		// 查询是小坤坤(用户名)的信息,这个用户名 应该是前台(浏览器) 用户 传过来的 -- 模拟
		Student student = studentDaoImpl.QueryByUsername("小坤坤");
		// 判断用户名是否存在
		if (student.getName() == null) {
			System.out.println("账号不存在");
		}
		// else 就是账号存在
		else {
			// 判断这个账号的密码是否正确 (这个密码应该是前台(浏览器) 用户 传过来的)
			if (!"8848".equals(student.getPassword())) {
				System.err.println("密码错误");
			} else {
				System.out.println("登录成功");
			}
		}
	}
 
事务
	@Test
	public void Testtrans() throws Exception {
		Connection connection = null;
		PreparedStatement ps = null;
		PreparedStatement ps2 = null;
		try {
			connection = JDBCUtil2.Instance().getconn();
			// 不提交事务 (sql执行了,改变了数据库的数据,但是后面没有写提交事务数据库就不能有变化),
			connection.setAutoCommit(false);
			String sql = "update bank set money=money-1000 where name='过儿'";
			ps = connection.prepareStatement(sql);
			ps.execute();
			// 在这个位置 出现异常
			int a=0/0;
			String sql2 = "update bank set money=money+1000 where name='姑姑'";
			ps2 = connection.prepareStatement(sql2);
			ps2.execute();
			// 提交事物 (数据库可以发生变化了)
			connection.commit();
		} catch (Exception e) {
			// 回滚 (你数据库改变了之后我还是可以回滚)
			/*当我们把自动提交关闭,那sql就不是提交执行,于是我们一定要记住,当我们一个整体功能完成之后,自己要手动进行提交;
			--conn.commit但是失败之后,要记住数据回滚*/
			connection.rollback();
		} finally {
			ps2.close();
			ps.close();
			connection.close();
		}
	}
 
ACID (面试)
 事务 : 一组操作 要么都成功 要么都失败
 事务具有4个特征,分别是原子性、一致性、隔离性和持久性,简称事务的ACID特性;
 原子性(atomicity) :一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作
 一致性(consistency) : 一个事务执行前后,数据库都处于一致性状态
 隔离性(isolation): 每一个事务都是单独的,事务和事务之间不影响
 持久性(durability): 事务执行完了, 持久化到数据库
链接池
概念

 你创建了一个池塘 池塘里面你放了很多链接 用完了就放回去 -->节省开关链接的时间
实现
在Java中,连接池使用javax.sql.DataSource接口来表示连接池,这里的DataSource就是连接池,连接池就是DataSource。
 DataSource是接口,和JDBC一样,是Sun公司开发的一套接口,需要各大厂商实现;
 需要导入相应包—导包…
 所以使用连接池,首先需要导包;
常用的DataSource的实现有下面两种方式:
 DBCP: Spring推荐的(Spring框架已经集成DBCP)
 C3P0: Hibernate推荐的(早期)(Hibernate框架已经集成C3P0)持久层
DBCP连接池实现
1.导入jar包
 commons-dbcp-1.3.jar,commons-pool-1.5.6.jar
2.代码
 BasicDataSource就是DBCP的连接池实现
第一种配置方式
public class JDBCUtil {
	// 构造方法私有化
	private JDBCUtil() {
	};
	private static JDBCUtil instance;
	// 一启动就加载驱动 只执行一次
	static Properties ps = null;
	static BasicDataSource ds = null;
	static {
		ps = new Properties();
		try {
			ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
			ds = new BasicDataSource();
			ds.setDriverClassName(ps.getProperty("dirverClassName"));
			ds.setUsername(ps.getProperty("username"));
			ds.setPassword(ps.getProperty("password"));
			ds.setUrl(ps.getProperty("url"));
		} catch (IOException e) {
			e.printStackTrace();
		}
/*		 try {
		 		ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
		 		Class.forName(ps.getProperty("dirverClassName"));
		 } catch (Exception e) {
		 		e.printStackTrace();
		 }*/
		instance = new JDBCUtil();
	}
	public static JDBCUtil Instance() {
		return instance;
	}
	// 写加载数据库的驱动
	public Connection getconn() {
		Connection connection = null;
		try {
			//换成新的获取连接池的方式
			connection = ds.getConnection();
			// connection = DriverManager.getConnection(ps.getProperty("url"),
			// ps.getProperty("username"), ps.getProperty("password"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connection;
	}
	// 关闭资源
	public void close(ResultSet rs, Statement State, Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (State != null) {
					State.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null) {
						conn.close();
					}
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
 
public class test {
	public static void main(String[] args) {
		Connection connection = JDBCUtil.Instance().getconn();
		try {
			String sql = "update bank set money=money-500 where name='过儿'";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
 
第二种配置方式
public class JDBCUtil2 {
	// 构造方法私有化
	private JDBCUtil2() {
	};
	private static JDBCUtil2 instance;
	// 一启动就加载驱动 只执行一次
	static Properties ps = null;
	static DataSource ds = null;
	static {
		ps = new Properties();
		try {
			ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
			// 创建连接池
			ds = BasicDataSourceFactory.createDataSource(ps);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// try {
		// 		ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
		// 		Class.forName(ps.getProperty("dirverClassName"));
		// } catch (Exception e) {
		// 		e.printStackTrace();
		// }
		instance = new JDBCUtil2();
	}
	public static JDBCUtil2 Instance() {
		return instance;
	}
	// 写加载数据库的驱动
	public Connection getconn() {
		Connection connection = null;
		try {
			//换成新的获取连接池的方式
			connection = ds.getConnection();
			// connection = DriverManager.getConnection(ps.getProperty("url"),
			// ps.getProperty("username"), ps.getProperty("password"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connection;
	}
	// 关闭资源
	public void close(ResultSet rs, Statement State, Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (State != null) {
					State.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null) {
						conn.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
 
public class test {
	public static void main(String[] args) {
		Connection connection = JDBCUtil2.Instance().getconn();
		try {
			String sql = "update bank set money=money-500 where name='过儿'";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
 
返回主键
场景举例:先后添加product和product_stock时,需要拿到product插入时自增的id存到product_stock的product_id里
看文档做
StudentDaoImpl
	@Override
	public void insert(Student stu) {
		Connection conn = JDBCUtil.Instance().getconn();
		PreparedStatement ps = null;
		try {
			String sql = "insert into student(name,password) values(?,?)";
			ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			ps.setString(1, stu.getName());
			ps.setString(2, stu.getPassword());
			ps.executeUpdate();
			ResultSet rs = ps.getGeneratedKeys();
			while (rs.next()) {
				System.err.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
 
JDBCTest
	@Test
	public void addStudent() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		Student stu = new Student();
		stu.setName("小波波");
		stu.setPassword("857857958958");
		studentDaoImpl.insert(stu);
	}
 
BaseDao的抽取
BaseDao
public class BaseDao {
	public void excuteUpdate(String sql, Object... objects) {
		Connection conn = JDBCUtil2.Instance().getconn();
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < objects.length; i++) {
				ps.setObject(i + 1, objects[i]);
			}
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil2.Instance().close(null, ps, conn);
		}
	}
}
 
实现类:
public class StudentDaoImpl extends BaseDao  implements IStudentDao{
    
    @Override
	public void insert(Student stu) {
		String  sql="insert into student(name,password) values(?,?)";
		excuteUpdate(sql, stu.getName(),stu.getPassword());
	}
	@Override
	public void update(Student stu) {
		String sql = "update student set name=?,password=? where id =?";
		excuteUpdate(sql, stu.getName(),stu.getPassword(),stu.getId());
	}
	@Override
	public void delete(Student stu) {
		String sql = "delete from student where id = ?";
		excuteUpdate(sql, stu.getId());
	}
}
 
JDBCTest
	@Test
	public void addStudent() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		Student stu = new Student();
		stu.setName("小波波");
		stu.setPassword("857857");
		stu.setId(254172);
//		studentDaoImpl.insert(stu);
//		studentDaoImpl.delete(stu);
		studentDaoImpl.update(stu);
	}
                




![排序算法:【选择排序]](https://img-blog.csdnimg.cn/direct/abf8c24ad7a44b54b333ffd9475c20ff.png)












