JDBC基本知识--接口类型,Juint注入,批处理,自增序列,分页查询

一、JDBC的原理

1、概念

  Java DataBase Connectivity:java数据库连接技术,简称JDBC.

    它是使用java语言编写的一套API,为多种关系型数据库提供了统一接口。 同时,也是一个“低级”接口,在其之上可以使用“高级”接口,更方便的连接数据库。

 2、目的

      为了给程序员提供同一种方式连接不同的数据库

      (提供一个与任何数据库连接的java界面)

 3、原理

   JDBC负责提供接口

      数据库厂商使用自己数据库的特点来实现接口。      

      程序员调用接口,实际上底层调用数据库厂商实现的部分

实际工作过程

(1)先将驱动包导入项目下(引用和复制到项目下两种方式)  

  (2)加载驱动,建立连接

  (3)使用驱动管理类型获取Sql语句执行对象

  (4)编写SQL语句,执行SQL语句

  (5)处理结果集

  (6)关闭连接  

 4、接口与类型

   (1)驱动管理类型:DriverManager

   static Connection getConnection(url,user,password)

      作用:  通过地址,数据库用户名,用户密码-----获取连接对象

   (2)连接接口:Connection

    Statement createStatement()

      作用:获取一个SQL语句编译对象

  

Statement st=conn.createStatement();

       PreparedStatement  prepareStatement(String sql)

作用:获取一个SQL语句预编译对象  

PreparedStatement ps=conn.prepareStatement(insert);

   (3)SQL语句对象接口:

Statement:  用于编译静态SQL语句(编译多次)

Statement st=conn.createStatement();

boolean execute(String sql):用来执行DDL语言

public static boolean login(String user,String pwd){

ResultSet executeQuery(String sql):用于执行DQL语言

String sql="select * from t_t01 where tname='zs'";

ResultSet rs=st.executeQuery(sql);

int executeUpdate(String sql):用于执行DML语言

String sql="update t_t02 set tsalary='3500'where tname='zs'";

int rs=st.executeUpdate(sql);

ps.executeUpdate();

void addBatch(String sql):添加批处理

ps.addBatch();

     if(i%22==0){

     //执行一次批处理

     ps.executeBatch();

     }

    int[] executeBatch(): 执行批处理

PreparedStatement:用于编译静态SQL语句,是Statement的一个子类型,执行效率比Statement要高(只编译一次)

//添加手动批处理

conn.setAutoCommit(false);

习题:JDBC_day02

package com.hyxy.jdbc.day02;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestBatch01 {
	@Test
	public void TestStatement02(){
		try {
			Statement stat=conn.createStatement();
			long start=System.currentTimeMillis();
			conn.setAutoCommit(false);
			for(int i=0;i<100;i++){
				String account_idcard=10000000000000000L+(long)(Math.random()*100000000000000L)+"";
				double money=Math.random()*1000;
				String account_phone=10000000000L+(long)(Math.random()*90000000000L)+"";
				String sql="insert into account_info values(null,'"+account_idcard+"',"+money+",'"+account_phone+"')";
			//添加批处理
				stat.addBatch(sql);
				if(i%22==0){
					stat.executeBatch();
					conn.commit();
					stat.executeBatch();
				}			
			}
			//将批处理剩余的不满的22条记录的一次性执行出来
			stat.executeBatch();
			conn.commit();
			long end=System.currentTimeMillis();
			System.out.println("statement批处理时间:"+(end-start));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testpreparedStatement02(){		
		try {
			String sql="insert into account_info values(null,?,?,?)";
			PreparedStatement ps=conn.prepareStatement(sql);
		long start=System.currentTimeMillis();
		//添加手动批处理
		conn.setAutoCommit(false);
		for(int i=0;i<100;i++){
			String account_idcard=1000000000000000L+(long)(Math.random()*900000000000000L)+"";
			double money=Math.random()*1000;
			String account_phone=10000000000L+(long)(Math.random()*90000000000L)+"";
			ps.setString(1, account_idcard);
			ps.setDouble(2, money);
			ps.setString(3, account_phone);
			//添加批处理
			ps.addBatch();
			if(i%22==0){
				//执行一次处理
				ps.executeBatch();
				conn.commit();
				ps.executeBatch();
			}
		}
		ps.executeBatch();
		conn.commit();
		long end=System.currentTimeMillis();
		System.out.println("preparement批处理时间:"+(end-start));
		
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	@Test
	//插入100条记录不用批处理
	public void testStatement01(){
		try {
			Statement stat=conn.createStatement();
			long start=System.currentTimeMillis();
			for(int i=0;i<100;i++){
				String account_idcard=10000000000L+(long)(Math.random()*90000000000L)+"";
				double money=Math.random()*1000;
				String account_phone=10000000000L+(long)(Math.random()*90000000000L)+"";
				String sql="insert into account_info values(null,'"+account_idcard+"',"+money+",'"+account_phone+"')";
			stat.executeUpdate(sql);
			}
			long end=System.currentTimeMillis();
			System.out.println("时间毫秒数:"+(end-start));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testPreparedStatement01(){
		try {
			String sql="insert into account_info values(null,?,?,?)";		
			PreparedStatement  ps=conn.prepareStatement(sql);
		long start=System.currentTimeMillis();
		for(int i=0;i<100;i++){
			String account_idcard=1000000000000000L+(long)(Math.random()*9000000000000000L)+"";
			double money=Math.random()*1000;
			String account_phone=10000000000L+(long)(Math.random()*90000000000L)+"";
		ps.setString(1, account_idcard);
		ps.setDouble(2, money);
		ps.setString(3, account_phone);
		ps.executeUpdate();
		}
		long end=System.currentTimeMillis();
		System.out.println("时间毫秒数:"+(end-start));
		
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	private Connection conn;
@Before 
	public void connectionDatabase(){
	try {
		conn=DBUtil.getConnection();
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	}
@After
	public void closeDatabase(){
	DBUtil.closeConnection(conn);
}


}

    (4)结果集接口:ResultSet

      在进行DQL操作时, 将查询的所有记录信息封装到ResultSet对象中 .

    boolean next(): 询问结果集对象中是否有下一行记录。

                 如果返回true,光标会自动移到下一行。    

    while(rs.next()){  

还提供了一些数据库类型转java数据类型的方法:

     int getInt(int columnIndex)/getInt(String columnName)

     double getDouble(int columnIndex)/getDouble(String columnName)

     String getString(int columnIndex)/getString(String columnName)

     Date getDate(int columnIndex)/getDate(String columnName)

       .........

5、驱动

   Oracle

      jar包:ojdbc5.jar/ojdbc14.jar

      Class.forName("oracle.jdbc.driver.OracleDriver");

      

   Mysql

      jar包: mysql-connector-java-5.1.7-bin.jar

      Class.forName("com.mysql.jdbc.Driver");

二、JDBC编程基础

     .......

三、工具类的封装DBUtil

      从上述练习中发现,每次都需要加载驱动,建立链接。

      其中的参数我们书写的次数比较多。   

 工具类的封装

 1、设置静态成员变量

 2、使用静态块进行加载资源

 3、将连接数据库操作单独封装一个工具方法

 4、将关闭数据库操作单独封装一个工具方法

数据库的工具类:使用Properties读取配置文件的方式

 方法1:   

     为了方便,为了节省资源,我们可以使用静态块来加载驱动,将参数值当成类的静态属性进行封装。 (加载一次就可以)  

 方法2:

     使用Properties 读取配置文件里的信息(将可能需要改变的信息存储在配置文件中)  

 

通常情况下都会选择方法2:   

 InputStream is=DBUtil02.class.getClassLoader().getResourceAsStream("db.properties");

Properties prop=new Properties();

prop.load(is);

river=prop.getProperty("driver");

练习在DBUtil02

package com.hyxy.jdbc.day02;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/*数据库的工具类:使用properties读取配置文件的方式*/
public class DBUtil02 {
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	static {
		try {
			/*先使用Properties读取配置文件里的信息*/
			InputStream is=DBUtil02.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop=new Properties();
			//将流里的信息加载到对象上
			prop.load(is);
			driver=prop.getProperty("driver");
			url=prop.getProperty("url");
			password=prop.getProperty("password");
			user=prop.getProperty("user");
			
			//加载驱动类型
			Class.forName(driver);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/*连接数据库的工具方法
	 * @return 连接成功后的连接对象
	 * @throws SQLException*/
	public static Connection getConnection() throws SQLException{
		return DriverManager.getConnection(url, user, password);
		}
		/*关闭连接操作的工具方法
		 * @param conn要关闭的连接对象
		 * 返回值是要关闭的连接对象*/
		
		public static void closeConnection(Connection conn){
			if(conn!=null){
				try {
					conn.close();
				} catch (SQLException e) {					
					e.printStackTrace();
				}
			}
		}
		/*测试连接方法的功能是否有效
		 * @param args*/
		public static void main(String[] args) {
			try {
				Connection conn=getConnection();
				System.out.println(conn);
				closeConnection(conn);
			} catch (SQLException e) {			
				e.printStackTrace();
			}
		}
}

   四:异常

  jdbc发生的异常一般都是SQLException或者是其子类异常是检查性异常。    

使用try-catch机制处理一下。

  finally里通常用来进行关闭数据库操作。

五、SQL注入:(injection)

   在使用Statement时,因为Statement会对静态SQL语句进行编译, 有可能会改变SQL语句的结构。因此有注入安全隐患。

    创建一个表  login_info

  字段: login_id  int           主键约束  序列自增

        login_user  varchar(20)   唯一约束

        login_pwd  varchar(50)   非空约束

        login_phone varchar(11)

 插入两条记录:

      1001,'zhangsan123','111111','13100001111'

      1002,'lisi123456','888888','13700001111'                  

create table login_info(

login_id int primary key auto_increment,

login_user varchar(20) unique,

login_pwd varchar(50) not null,

login_phone varchar(11)

);

insert into login_info values(1001,'zhangsan123','111111','13100001111');     

insert into login_info values(1002,'lisi123456','888888','13700001111');  

select * from login_user='zhangsan123' and login_pwd='wang';

 

由上面两个条件的sql结构

变成了下面的三个条件的结构,就是SQL注入现象

select * from login_user='zhangsan123' and login_pwd='wang' or 'a' = 'a';

后来改用Statement的子类PreparedStatement来代替。

PreparedStatement叫预编译sql语句类型,对静态sql语句编译一次。编译后无法再改变sql语句结构

六、PreparedStatement的用法

      可以对静态SQL语句使用问号"?"充当占位符。    

   如: 

  select * from login_info  where login_user = ? and login_pwd= ?

   使用此类中提供的类型转换方法进行给问号赋值

  ps.setInt(int parameterIndex,int value)

  ps.setDouble(int parameterIndex,double value)

  ps.setString(int parameterIndex,String value)

  ps.setDate(int parameterIndex,Date value)

  .........

ps.setInt(1,9100);

ps.setString(2,"superman");

ps.setString(3,"saleman");

ps.setInt(4, 9001);

ps.setDate(5, Date.valueOf("1987-10-12"));

ps.setDouble(6,3000);

ps.setDouble(7,20);

今天的习题代码是eclipse--day01

package com.hyxy.jdbc_day01;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;

/*预编译SQL语句类型的学习
 * PreparedStatement:是Statement的子类*/
public class TestPreparedStatementDemo01 {
	public static void main(String[] args) {
		/*向员工表中插入一条记录
		 * 9100,'superman','salesman','9001',null,3000.0,20,10
		 * */
		Connection conn=null;
		try {
			conn=DBUtil02.getConnection();
			String insert="insert into emp values(?,?,?,?,?,?,?,?)";
			PreparedStatement ps=conn.prepareStatement(insert);
			ps.setInt(1,9100);
			ps.setString(2,"superman");
			ps.setString(3,"saleman");
			ps.setInt(4, 9001);
			ps.setDate(5, Date.valueOf("1987-10-12"));
			ps.setDouble(6,3000);
			ps.setDouble(7,20);
			ps.setInt(8,10);
			//执行sql语句
			ps.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			DBUtil02.closeConnection(conn);
		}		
	}
}

 新课

一、Junit: java方法的另外一种测试方式

  (1)导入Junit4的jar

  (2)在非静态方法上添加注解@Test

  (3)选中非静态方法的名称右键运行或者在类的树形结构中选中方法运行。       

   @Before:此注解的位置也是非静态方法上。

  运行时机:在运行@Test注解方法前会自动执行。       

   @After:在运行@Test注解方法后会执行

二、JDBC对事务的支持

      事务要满足四个条件:ACID

      原子性:一个事务,要么成功,要么回滚(撤回)

      一致性:事务开始前的数据要和结束后的数据保持一致。

      隔离性:一个事务正在进行,另外的事务要等待。

      持久性:事务提交后,数据的改变是永久性的。

  手动提交:

JDBC对DML语言的操作是默认提交的,当有多个DML操作时,我们应该取消自动提交,改为手动提交 。 

   Connection接口提供了一个方法

   void setAutoCommit(boolean flag):

   true:表示自动提交

   false:表示取消自动提交

   void commit(): 提交事务

   void rollback():事务回滚

三、批处理

      在进行插入数据操作时,有的时候,一条一条的操作,比较耗时。

      我们可以进行批量的插入操作。  

   Statement:

        addBatch(String sql)

        executeBatch():

   PreparedStatement:

        addBatch():

        executeBatch():      

四、新课

1、oracle学习版安装

   (1)添加SYS和System用户的口令

   (2)我们要启动数据库主页,使用System进行登录

   (3)创建一个普通用户scott,密码tiger

2、  连接方式

   (1)命令提示符界面

            选择自带的运行SQl命令行界面

            输入 conn  username/password

   (2)使用客户端sqldeveloper

            连接名:

            用户名:scott

            口令:

            主机名:ip

            端口号: tcp/ip协议,1521         /http协议的端口号默认是8080/80          

      SID:oracle特有的唯一标识符 xe/orcl

    (3)使用JDBC连接oralce数据库

 3、使用

     数据类型:   数字类型

                        字符串类型

                        日期类型

     数字类型:number

        number(m):表示最长m位整数

        number(m,n):表示整数位最长m-n,小数点后保留n位。

      字符串类型:

        char(m):固定长度字符串类型     

        varchar(m)

        varchar2(m):oracle独有的一个可变字符串类型

        Blob   

      日期类型:date:  年月日时分秒

      timestamp:可以精确到纳秒        

   作业:

   在TestOracle里使用Junit进行

    完成增删改查操作

    查: 通过tid查询某一条记录

    查全部            

   testAdd()

   testByTid()

   testAll()

   testUpdate()

   testdeleteByTid()    

package com.hyxy.jdbc.day03;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


/* 在TestOracle里使用Junit进行
    完成增删改查操作
    查: 通过tid查询某一条记录
    查全部            
   testAdd()
   testByTid()
   testAll()
   testUpdate()
   testdeleteByTid() 
     */
public class TestOracle {
	private Connection conn;
	@Test
	public void testBytid(){
		try {
			String sql="select * from t_01 where tid=?";
			PreparedStatement ps=conn.prepareStatement(sql);
			ps.setInt(1,1002);
			ResultSet rs=ps.executeQuery();
			if(rs.next()){//查询一条用if
				System.out.println(rs.getInt(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getDouble(5));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testUpdate(){
		try {
			String sql="update t_01 set tname=? where tid=?";
			PreparedStatement ps = conn.prepareStatement(sql);			
			ps.setString(1, "wanger");
			ps.setInt(2,1001);
			ps.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testdeleteByTid(){
		try {
			String sql="delete from t_01 where tid=1003";
			PreparedStatement ps = conn.prepareStatement(sql);		
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	@Test
	public void testAll(){
		try {
			String sql="select * from t_01";
			PreparedStatement ps=conn.prepareStatement(sql);
			ResultSet rs=ps.executeQuery();
			while(rs.next()){//查询多条用while
				System.out.println(rs.getInt(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getDouble(5));		
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testAdd(){
		try {
			//插入2条数据
			String sql="insert into t_01 values(?,?,?,?,?)";
			PreparedStatement ps=conn.prepareStatement(sql);
			ps.setInt(1, 1002);
			ps.setString(2, "zhaoliu");
			ps.setString(3,"1230000000000000");
			ps.setString(4, "f");
			ps.setDouble(5,5000.0);
			ps.execute();
			ps.setInt(1, 1003);
			ps.setString(2, "zhaoqi");
			ps.setString(3,"1240000000000000");
			ps.setString(4, "m");
			ps.setDouble(5,6000.0);
			ps.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Before
	public void connectionDatabase(){
		try {
			conn=DBUtil.getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@After
	public void colseConnection(){
		DBUtil.closeConnection(conn);
	}
}

新课

一.Mysql自增序列的获取

有的时候,两张表中的字段可能有关系,当向一张表插入数据时,另外一张表可能需要这张表的数据。

Student

Sid     sname       sage

1001    ‘zhangsan’   23

Sc选课表

Scid     sid        scname

1       1001       ‘高数

分页查询---TestByPage.java

limit  brgin , size.

limit  size;

package com.hyxy.jdbc.day03;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;



public class TestByPage {
	@Test
	public void findByPage(){
		try {
			/*查询员工表的第二页数据,按照部门升序每页5条*/
			String sql="select * from emp order by deptno limit ?,?";
			PreparedStatement ps=conn.prepareStatement(sql);
			/*page:n页数
			 * 第n页的数据
			 * size:每页最大数
			 * begin :size*(page-1)*/
			
			ps.setInt(1,5*(2-1));
			ps.setInt(2, 5);
			ResultSet rs=ps.executeQuery();
			while(rs.next()){//查询一条用if
				System.out.println(rs.getInt("deptno")+","+rs.getInt("empno")+","+rs.getString("ename"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

private Connection conn;
@Before
public void connectionDatabase(){
	try {
		conn=DBUtil.getConnection();
	} catch (Exception e) {
		e.printStackTrace();
	}
}
@After
public void colseConnection(){
	DBUtil.closeConnection(conn);
}
}

---------------------------------------------------------------------------------------------------------------------------------

新课2

思考:表,记录与类,对象关系   

三.DAO(Data  Access  Object)思想:数据访问对象

在开发时,我们一定会使用数据库,编程语言的APP

                 存储

APP--------------------->数据库

       <---------------------

                获取

ORM:对象关系映射(Object  relation  mapping)

表的一条记录映射成类的一个对象

类的一个对象映射成一个表的记录

开发思路:

现在主流开发模式:MVC架构思想

Model模型层--业务层,持久层

View视图层--用户所能操作与看到的部分

Controller控制层--控制用户操作与模型层的逻辑走向部分

程序与数据库交互的层次称之为持久层

第一步: 通过ORM(对象关系映射)设计实体类

第二步:设计一个接口(持久层的各个功能),提供与数据库交互的各个功能

第三步:编写此接口的实现类,完善功能逻辑

第四步:提供Dao工厂类型

四.在开发项目时需要注意的:

包的设计:域名后缀.域名.项目名.模块名

com.hyxy.jdbc.util

com.hyxy.jdbc.entity

com.hyxy.jdbc.dao

com.hyxy.jdbc.dao.impl

com.hyxy.jdbc.test     

习题:  JDBC_day003和JDBC_day03

---------------------------------------------------------------------------------------------------------------------------------------------

Oracle的分页查询

1.按照排序规则

select * from emp order by dptno

2.在分配行号               

    

select rownum  rn,e.* from   (select * from emp order by dptno) e;

3.分页查询,可以进行范围确定

select  from

select rownum  rn,e.* from   (select * from emp order by dptno

) e where rn between 6 and 10;

                     

猜你喜欢

转载自blog.csdn.net/qq_42721694/article/details/82807265