数据库简介
关系型数据库:Oracle,Mysql,SQL server/一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织
关系型数据库的最大特点就是事务的一致性:传统的关系型数据库读写操作都是事务的,具有ACID的特点,这个特性使得关系型数据库可以用于几乎所有对一致性有要求的系统中,如典型的银行系统。
非关系型数据库: MongoDB CouchDB
非关系型数据库中,其实实现大部分都比较简单,除了一些共性外,很大一部分都是针对某些特定的应用需求出现的,因此,对于该类应用,具有极高的性能
首先什么是JDBC
JDBC 是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据。JDBC代表Java数据库连接。
JDBC库中所包含的API通常与数据库使用于:
- 连接到数据库
- 创建SQL或MySQL语句
- 在数据库中执行SQL或MySQL查询
- 查看和修改数据库中的数据记录
JDBC需要
- JAVA(JDK)安装
- 数据库系统的安装(如:MySQL的安装)
- eclipse需要下载jar包,而IDEA用maven直接引入maven即可
JDBC常用的类和接口
1. Connection接口:代表数据库连接对象,每个Connection代表一个物理连接会话。要想访问数据库,必须先得到数据库连接。该接口的常用方法如下:
2.DriverManager 类
用于管理JDBC驱动的服务类。程序中使用该类的的主要功能是获取Connection对象
通过 getConnection() 方法可以建立连接,成功则经连接返回,否则抛出 SQLException 异常。
3.Statement 接口
Statement 接口用于在已经建立连接的基础上向数据库发送 SQL 语句。在 JDBC 中有 3 种 Statement 对象,分别是 Statement、PreparedStatement 和 CallableStatement 。
Statement 对象用于执 行不带参数的简单的 SQL 语句:
PreparedStatement 继承了 Statement,用来执行动态的 SQL 语句;
CallableStatement 继承了 PreparedStatement,用于执行对数据库的存储过程的调用
4.PreparedStatement 接口
PreparedStatement 接口继承了Statement接口,但是缺有很大的不同,一方面,PreparedStatement对象是经过预编译的,所以执行速度比Statement快很多
其次PreparedStatement继承了Statement接口,所以不但拥有Statement接口的方法,还有自己一套更完善的方法。用于设置发送给数据库以取代IN参数占位符的值,
并且PreparedStatement方法还可以避免SQL语句的注入和攻击,(我用过的注入就是and 1=1的形式,也是最简单的,这里不过多讨论)
它的方法如下
最后就是
5.ResultSet 接口
esultSet 接口类似于一个临时表,用来暂时存放数据库查询操作所获得的结果集。ResultSet 实例具有指向当前数据行的指针,
指针开始的位置在第一条记录的前面,通过 next() 方法可将指针向下移。
知道这些接口和类和方法后让我们来实际操作一下
jdbc:mysql://127.0.0.1:3306/数据库名字
package JDBC_test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Test { public static void main(String[] args) throws Exception{ //声明Connection对象 Connection con = null; //驱动程序名 String driver = "com.mysql.jdbc.Driver"; //URL指向要访问的数据库名test String url = "jdbc:mysql://127.0.0.1:3306/mysql"; //MySQL配置时的用户名 String user = "root"; //MySQL配置时的密码 String password = "root"; //遍历查询结果集 try { //加载驱动程序 Class.forName(driver); //1.getConnection()方法,连接MySQL数据库!! con = DriverManager.getConnection(url,user,password); if(!con.isClosed()) System.out.println("Succeeded connecting to the Database!"); //2.创建statement类对象,用来执行SQL语句!! Statement statement = con.createStatement(); //要执行的SQL语句 String sql = "select sno,sname,age,sex from student"; //3.ResultSet类,用来存放获取的结果集!! ResultSet rs = statement.executeQuery(sql); System.out.println("--------------------------------------"); System.out.println("执行结果如下所示:"); System.out.println("------------------------"); System.out.println("学号" + " " + "姓名" + " " + "性别" + " " + "年龄"); System.out.println("--------------------------------------"); String name= null; String id = null; String sex = null; String agr = null; while(rs.next()){ //获取sno这列数据 id = rs.getString("sno"); //获取sname这列数据 name = rs.getString("sname"); //获取sex这列数据 sex = rs.getString("sex"); //获取age这列数据 agr = rs.getString("age"); //输出结果 System.out.println(id + " " + name + " " + sex + " " + agr); } rs.close(); con.close(); } catch(ClassNotFoundException e) { //数据库驱动类异常处理 System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch(SQLException e) { //数据库连接失败异常处理 e.printStackTrace(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally{ System.out.println("数据库数据成功获取!!"); } } }
再来看一个,对比一下prepareStatement,会发现prepareStatement的占位符的方便
package mywebproject; import java.sql.*; public class LoginDao { public boolean login(String name,String pwd) throws ClassNotFoundException, SQLException { Statement st=null; Connection conn=null; ResultSet rs=null; PreparedStatement ps=null; boolean flag=false; try { Class.forName("com.mysql.cj.jdbc.Driver"); //2.获取数据库连接 String url="jdbc:mysql://localhost:3306/suzy?useSSL=false&serverTimezone=Asia/Shanghai"; String user="root"; String password="root"; conn=DriverManager.getConnection(url, user, password); //3.获取数据库操作对象 String sql="select username from t_user where username= ? and password = ?"; //sql语句进行预编译 ps=conn.prepareStatement(sql); //对sql语句进行赋值 ps.setString(1, name); ps.setString(2, pwd); rs=ps.executeQuery(); if(rs.next()) { flag=true; } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(rs!=null) { rs.close(); } if(ps!=null) { ps.close(); } if(conn!=null) { conn.close(); } } return flag; } }
一个login用户跳转的简单运用jdbc,(因为是jdbc的练习,就绝大部分是靠jdbc)
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录界面</title> </head> <body style="background: url(image/2.jpg)" align="center"> <font color="green" size="5px">登录界面-代码改变世界</font><br><br> <form action="jaincha.jsp" method="post"> 用户名:<input type="text" name="name"><br><br> 密码:<input type="password" name="pwd"><br><br> <input type="submit" value="登录"><br><br> </form> </body> </html>
登录不管成功失败跳转到
jiancha.jsp
找到有这个账号密码就有next没找到就没next
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.sql.*" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Server Page Depend !</title> </head> <body> <h3>Which Pae will be depend by the user's message!</h3> <% String name=request.getParameter("name");//获取name的参数值 String password=request.getParameter("pwd");//获取password的参数值 %> <% Class.forName("com.mysql.jdbc.Driver");//加载mysql驱动 Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");//localhost是本机地址,3306是端口号,最后是用户名和密码 Statement stmt=conn.createStatement();//实例化Statement对象 String queryNumberSQL="SELECT * from p_user where username='"+name+"' and password='"+password+"'"; ResultSet rs=stmt.executeQuery(queryNumberSQL);//执行数据库查询操作并获取结果集 boolean flag=false;//初始化flag if(rs.next()){//判断结果 flag=true; session.setAttribute("UserName", name);//将name的内容赋值给UserName }else{ flag=false; } %> <% if(flag){ %> <jsp:forward page="login_success.jsp"></jsp:forward>//跳转页面 <% }else{ %> <jsp:forward page="login_failed.jsp"></jsp:forward>//跳转页面 <% } //关闭上面的几个对象,注意关闭顺序,最后使用的先关闭 rs.close(); stmt.close(); conn.close(); %> </body> </html>
loginsuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>User Login Success Page!</title> </head> <body> <hr><br> <h1>Login Success!</h1><br> <font color="green">Welcome <%=session.getAttribute("UserName") %>!</font> <h3 align="center">your persional Message is:</h3> <% out.println("Name:"+session.getAttribute("UserName")); %> <font color="red"><a href="login.jsp">Click me</a> to log out!</font> </body> </html>
输入abc abc
否则就是没有就是faile跳转
loginfaile.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login Failed Page!</title>
</head>
<body>
<hr>
<br>
<h1><font color="red">Sorry,Login Failed</font></h1><br>
<font color="red"><a href="login.jsp">Click me</a> to login!</font>
</body>
</html>
同理注册就是跳转到添加用户到数据库的功能界面。有空再实现以下即可
当然还可以很多优化,比如什么账号密码不小于几位数急用js实现以下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>登录页面</title> </head> <body> <form method="post" action="jiancha" onsubmit="return checkform();"> 用户名:<input type="text" id="username" name="username" /> <br> 密码: <input type="password" id="password" name="password" /> <br> <span id="info1"></span> <br> <input type="submit" value="登录" /> </form> <script> function checkform() { var msg = ""; var unlen = document.getElementById("username").value.length; if(unlen < 6) { msg += "用户名长度不能小于6"; } var passwordlen = document.getElementById("password").value.length; if(passwordlen < 6) { msg += "<br>密码长度不能小于6"; } if(msg.length == 0) { return true; } else { document.getElementById("info1").innerHTML = "<span style='color:red'>" + msg + "</span>"; return false; } } </script> </body> </html>
看完上面觉得太复杂,不想每次写
所以可以写一个工具类
dbtool.java
package sql_dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class Dbtool { //mysql5.x final static String classforname = "com.mysql.jdbc.Driver"; final static String url = "jdbc:mysql://localhost/logindemo?user=root&password=root&useSSL=true"; // //mysql 8.x // final static String classforname = "com.mysql.cj.jdbc.Driver"; // final static String url = "jdbc:mysql://localhost/logindemo?user=root&password=root"; private Connection conn = null; private Statement stmt = null; private ResultSet rs = null; /*** * * * @param sql * @return */ public int executeUpdate(String sql) { int rtv = 0; try { Class.forName(classforname); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); rtv = stmt.executeUpdate(sql); } catch (Exception e) { e.printStackTrace(); } return rtv; } /*** * author:denny * * @param sql * @return */ public ResultSet executeQuery(String sql) { try { Class.forName(classforname); conn = DriverManager.getConnection(url); stmt = null; stmt = conn.createStatement(); rs = stmt.executeQuery(sql); } catch (Exception e) { e.printStackTrace(); } return rs; } /*** * author:denny * * @param sql * @return 返回自增id信息 */ public int executeUpdateReturnLAST_INSERT_ID(String sql) { int rtv = 0;// 数据库受影响的行数 try { Class.forName(classforname); conn = DriverManager.getConnection(url); stmt = conn.createStatement(); stmt.executeUpdate(sql); // 增加记录后,立刻查询自增id ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID()as num"); rs.next(); rtv = rs.getInt("num"); //System.out.println("刚刚增加的id=" + rtv); } catch (Exception e) { e.printStackTrace(); } return rtv; } public void close() { if (rs != null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if (stmt != null) { try { stmt.close(); } catch (Exception e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } } }
同理可以写很多这样的工具类功能,而我们只需要再重复用这些工具类即可
如(当然这里面也引用了md5增加密码安全性)
package sicnu.cs.demo; import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.codec.digest.DigestUtils; import sql_dao.Dbtool; /** * Servlet implementation class Login */ @WebServlet("/logincheckpro") public class Login extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Login() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("I am get").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //控制器,无需HTML 嵌入java处理业务 //request 是一个内置对象 ,默认就可以访问 ,作用就是读取用户信息 String username = request.getParameter("username"); //输入框的内容 String password = request.getParameter("password"); username = new String(username.getBytes("ISO-8859-1"), "utf-8"); //密码的隐藏 password= DigestUtils.md5Hex(password); //out是内置对象,PrintWriter System.out.println("username=" + username + ",password=" + password); String sql = "SELECT `id`, `username`, `password` FROM `user` where username='" + username + "'"; System.out.println("sql=" + sql); Dbtool dbtool = new Dbtool(); ResultSet rs = dbtool.executeQuery(sql); //加强版改进 String passwordInDb=""; /* while(rs.next()){//rs.next()返回一个布尔值,表示是否还有查询的结果 System.out.println(rs.getString("username")); out.println(rs.getString("username")); //内置对象,页面刷新内容 } */ try { if(rs.next()) { //代表可以登录 System.out.println(rs.getString("username")); //rs是数据库回来的结果集 passwordInDb=rs.getString("password"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } dbtool.close(); if(password.equals(passwordInDb)) { //让浏览器自己跳转,不够友好 // response.sendRedirect("index.jsp") //内置对象session 默认20分钟,一个用户一个独立的Session0 //!!!!!!!!!!!!!!!!!!!加按这个 HttpSession session = request.getSession(); session.setAttribute("demo-user", username); //Attribute生命周期只能到达Dispatcher分配器之后的页面,而jumper里面又会再跳转,所以Attribute失效,这个就和session的20分钟不同 //可以在跳转的跳转的页面尝试打印如info就能知道为null request.setAttribute("url", "index.jsp"); request.setAttribute("info", "登录成功,即将跳转到首页"); request.getRequestDispatcher("jumper.jsp").forward(request, response); }else{ request.setAttribute("url", "login.jsp"); request.setAttribute("info", "登录信息有误"); request.getRequestDispatcher("jumper.jsp").forward(request, response); } } }