Home >Database >Mysql Tutorial >web day17 JDBC入门,DAO模式mySQL时间类型转换,批处理_MySQL

web day17 JDBC入门,DAO模式mySQL时间类型转换,批处理_MySQL

WBOY
WBOYOriginal
2016-05-27 13:45:111833browse

\

JDBC入门

1.JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。

 

2.JDBC原理

 

最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!

 

3.JDBC核心类(接口)介绍

JDBC中的核心类有:DriverManager、Connection、Statement,和ResultSet

 

DriverManager(驱动管理器)的作用有两个:

注册驱动:这可以让JDBC知道要使用的是哪个驱动;

获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。

 

Connection对象表示连接,与数据库的通讯都是通过这个对象展开的:

Connection最为重要的一个方法就是用来获取Statement对象;

 

Statement是用来向数据库发送SQL语句的

voidexecuteUpdate(String sql):执行更新操作(insert、update、delete等);

ResultSetexecuteQuery(String sql):执行查询操作,数据库在执行查询后会把查询结果,查询结果就是ResultSet;

 

ResultSet对象表示查询结果集,只有在执行查询操作后才会有结果集的产生

booleannext():使“行光标”移动到下一行,并返回移动后的行是否存在

XXXgetXXX(int col):众多get方法,获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。

4.JDBC入门操作

A:导jar包:驱动!

B:加载驱动类:Class.forName(“类名”);

C:给出ur、username、password,其中url背下来!

D:使用DriverManager类来得到Connection对象!

4.1:mysql数据库的驱动jar包:mysql-connector-java-5.1.13-bin.jar

4.2:获取连接

获取连接需要两步:

一是使用DriverManager来注册驱动

:注册驱动:

就只有一句话:Class.forName(“com.mysql.jdbc.Driver”)

原理:源码中静态代码块中会把com.mysql.jdbc.Driver注册到DriverManager

DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

虽然可以注册驱动,属硬编码,依赖jar包,换数据库需要改代码

二是使用DriverManager来获取Connection对象。

:获取连接:

也只有一句代码:DriverManager.getConnection(url,username,password)

username和password为数据库用户名和密码

url:用来找到要连接数据库“网址”

mysql的url:jdbc:mysql://localhost:3306/mydb1

例:

Connectioncon =DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb1”,”root”,”123”);

4.3:获取Statement

Statementstmt = con.createStatement();

Statement是用来向数据库发送要执行的SQL语句的!

4.4 发送SQL增、删、改语句

Stringsql = “insert into user value(’zhangSan’, ’123’)”;

执行更新操作,即执行insert、update、delete,create table、alter table,drop table

intm = stmt.executeUpdate(sql);//m为影响的行数

4.5 发送SQL查询语句

Stringsql = “select * from user”;

ResultSetrs = stmt.executeQuery(sql);

executeQuery()方法返回的是ResultSet,ResultSet封装了查询结果,称之为结果集。

4.6 读取结果集中的数据

\

rs.next();//光标移动到第一行

rs.getInt(1);//获取第一行第一列的数据

常用方法:

ObjectgetObject(int col)

StringgetString(int col)

intgetInt(int col)

doublegetDouble(int col)

滚动结果集光标方法

voidbeforeFirst():把光标放到第一行的前面,这也是光标默认的位置;

voidafterLast():把光标放到最后一行的后面;

booleanfirst():把光标放到第一行的位置上,返回值表示调控光标是否成功;

booleanlast():把光标放到最后一行的位置上;

booleanisBeforeFirst():当前光标位置是否在第一行前面;

booleanisAfterLast():当前光标位置是否在最后一行的后面;

booleanisFirst():当前光标位置是否在第一行上;

booleanisLast():当前光标位置是否在最后一行上;

booleanprevious():把光标向上挪一行;

booleannext():把光标向下挪一行;

booleanrelative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;

booleanabsolute(int row):绝对位移,把光标移动到指定的行上;

intgetRow():返回当前光标所有行。

获取结果集元数据

得到元数据:rs.getMetaData(),

返回值为ResultSetMetaData;

获取结果集列数:int getColumnCount()

获取指定列的列名:String getColumnName(intcolIndex)

4.7 关闭资源

与IO流一样,关闭的顺序是先得到的后关闭,后得到的先关闭。

rs.close();

stmt.close();

con.close();

4.8 代码

public class Demo2 {
	/*
	 * 连接数据库,得到Connection就算成功!
	 * 对数据库做增、删、改
	 */
	@Test
	public void fun1() throws ClassNotFoundException, SQLException {
		/*
		 * 一、得到Connection
		 * 1. 准备四大参数
		 * 2. 加载驱动类
		 * 3. 得到Connection
		 */
		// 准备四大参数
		String driverClassName = "com.mysql.jdbc.Driver";
		// jdbc协议的格式!jdbc:工商的名称:子协议(由工商自己来规定)
		// 对mysql而言,它的子协议结构://主机:端口号/数据库名称
		String url = "jdbc:mysql://localhost:3306/mydb3";
		String username = "root";
		String password = "123";
		
		// 加载驱动类
		Class.forName(driverClassName);
		// 使用DriverManager,以及省下的3个参数,得到Connection
		Connection con = DriverManager.getConnection(url, username, password);
		
		/*
		 * 二、对数据库做增、删、改
		 * 1. 通过Connection对象创建Statement
		 * > Statement语句的发送器,它的功能就是向数据库发送sql语句!
		 * 2. 调用它的int executeUpdate(String sql),它可以发送DML、DDL
		 */
		// 1. 通过Connection得到Statement对象
		Statement stmt = con.createStatement();
		// 2. 使用Statement发送sql语句!
//		String sql = "INSERT INTO stu VALUES('ITCAST_0003', 'wangWu', 88, 'male')";
//		String sql = "UPDATE stu SET name='zhaoLiu', age=22, " +
//				"gender='female' WHERE number='ITCAST_0003'";
		String sql = "DELETE FROM stu";
		int r = stmt.executeUpdate(sql);
		System.out.println(r);
	}
	
	/**
	 * 执行查询
	 * @throws ClassNotFoundException 
	 * @throws SQLException 
	 */
	@Test
	public void fun2() throws ClassNotFoundException, SQLException {
		/*
		 * 一、得到Connection
		 * 二、得到Statement,发送select语句
		 * 三、对查询返回的“表格”进行解析!
		 */
		/*
		 * 一、得到连接
		 * 1. 准备四大连接参数
		 */
		String driverClassName = "com.mysql.jdbc.Driver";
		String url = "jdbc:mysql://localhost:3306/exam";
		String username = "root";
		String password = "123";
		
		/*
		 * 2. 加载驱动类
		 */
		Class.forName(driverClassName);
		/*
		 * 3. 通过省下的三个参数调用DriverManger的getConnection(),得到连接
		 */
		Connection con = DriverManager.getConnection(url, username, password);
		
		/*
		 * 二、得到Statement,执行select语句
		 * 1. 得到Statement对象:Connection的createStatement()方法
		 */
		Statement stmt = con.createStatement();
		/*
		 * 2. 调用Statement的ResultSet rs = executeQuery(String querySql)
		 */
		ResultSet rs = stmt.executeQuery("select * from emp");
		
		/*
		 * 三、解析ResultSet
		 * 1. 把行光标移动到第一行,可以调用next()方法完成!
		 */
		while(rs.next()) {//把光标向下移动一行,并判断下一行是否存在!
			int empno = rs.getInt(1);//通过列编号来获取该列的值!
			String ename = rs.getString("ename");//通过列名称来获取该列的值
			double sal = rs.getDouble("sal");
			
			System.out.println(empno +  ", " + ename + ", " + sal);
		}
		
		/*
		 * 四、关闭资源
		 * 倒关
		 */
		rs.close();
		stmt.close();
		con.close();//这个东东,必须要关,不关就死!
	}

4.9规范化代码

// 规范化
	@Test
	public void fun3() throws Exception {
		Connection con = null;//定义引用
		Statement stmt = null;
		ResultSet rs = null;
		try {
			/*
			 * 一、得到连接
			 */
			String driverClassName = "com.mysql.jdbc.Driver";
			String url = "jdbc:mysql://localhost:3306/exam";
			String username = "root";
			String password = "123";
			
			Class.forName(driverClassName);
			con = DriverManager.getConnection(url, username, password);//实例化
			
			/*
			 * 二、创建Statement
			 */
			stmt = con.createStatement();
			String sql = "select * from emp";
			rs = stmt.executeQuery(sql);
			
			rs.last();//把光标移动到最后一行

			rs.beforeFirst();
			
			/*
			 * 三、循环遍历rs,打印其中数据
			 * 
			 * getString()和getObject()是通用的!
			 */
//			while(rs.next()) {
//				System.out.println(rs.getObject(1) + ", " 
//						+ rs.getString("ename") + ", " + rs.getDouble("sal"));
//			}
			
			int count = rs.getMetaData().getColumnCount();
			while(rs.next()) {//遍历行
				for(int i = 1; i <= count; i++) {//遍历列
					System.out.print(rs.getString(i));
					if(i < count) {
						System.out.print(", ");
					}
				}
				System.out.println();
			}
			
		} catch(Exception e) {
			throw new RuntimeException(e);
		} finally {
			// 关闭
			if(rs != null) rs.close();
			if(stmt != null) stmt.close();
			if(con != null) con.close();
		}
		
	}
}

5.PreparedStatement的使用

它是Statement接口的子接口

优点:防SQL攻击,提高代码的可读性、可维护性,提高效率

使用:

给出SQL模板---所谓SQL模板就是有“?”的SQL语句,其中“?”就是参数

使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;

调用PreparedStatement的setXXX()系列方法为问号设置值

调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;

代码

		/*
		 * 一、得到PreparedStatement
		 * 1. 给出sql模板:所有的参数使用?来替代
		 * 2. 调用Connection方法,得到PreparedStatement
		 */
		String sql = "select * from t_user where username=? and password=?";
		PreparedStatement pstmt = con.prepareStatement(sql);
		
		/*
		 * 二、为参数赋值
		 */
		pstmt.setString(1, username);//给第1个问号赋值,值为username
		pstmt.setString(2, password);//给第2个问号赋值,值为password
		
		ResultSet rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句
		
		pstmt.setString(1, "liSi");
		pstmt.setString(2, "123");
		
		pstmt.executeQuery();



JdbcUtils工具类



作用:
连接数据库的四大参数是:驱动类、url、用户名,以及密码。这些参数都与特定数据库关联,
如果将来想更改数据库,那么就要去修改这四大参数,
那么为了不去修改代码,我们写一个JdbcUtils类,让它从配置文件中读取配置参数,然后创建连接对象。


工具代码v1.0

dbconfig.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=UTF8
username=root
password=123


public class JdbcUtils {
	private static Properties props = null;
	
	// 只在JdbcUtils类被加载时执行一次!
	static {
		// 给props进行初始化,即加载dbconfig.properties文件到props对象中
		try {
			InputStream in = JdbcUtils.class.getClassLoader()
					.getResourceAsStream("dbconfig.properties");//<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">配置文件路径在src目录下</span>

			props = new Properties();
			props.load(in);
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
		
		// 加载驱动类
		try {
			Class.forName(props.getProperty("driverClassName"));
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	// 获取连接!
	public static Connection getConnection() throws SQLException {
		// 得到Connection
		return DriverManager.getConnection(props.getProperty("url"),
				props.getProperty("username"), 
				props.getProperty("password"));
	}
}

UserDao(面向接口编程及DAO工厂)

DAO(Data Access Object)模式就是写一个类,把访问数据库的代码封装起来。DAO在数据库与业务逻辑(Service)之间。

实体域,即操作的对象,例如我们操作的表是user表,那么就需要先写一个User类;

DAO模式需要先提供一个DAO接口;

然后再提供一个DAO接口的实现类;

再编写一个DAO工厂,Service通过工厂来获取DAO实现。

修改项目:

1.把UserDao修改为接口,然后把原来的UserDao修改类名为UserDaoImpl

2.修改UserService中对UserDao的实例化:private UserDao userDao =DaoFactory.getUserDao()

3.创建DaoFactory,提供getUserDao()

代码

工厂类
/**
 * 通过配置文件得到dao实现类的名称!
 * 通过类名称,完成创建类对象!(反射完成的!)
 * @author cxf
 *
 */
public class DaoFactory {
	private static Properties props = null;
	static {
		// 加载配置文件内容到props对象中
		try {
			InputStream in = DaoFactory.class
					.getClassLoader().getResourceAsStream("dao.properties");
			props = new Properties();
			props.load(in);
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 返回一个具体UserDao的实现类对象
	 * @return
	 */
	public static UserDao getUserDao() {
		/**
		 * 给出一个配置文件,文件中给出UserDao接口的实现类名称!
		 * 我们这个方法,获取实现类的类名,通过反射完成创建对象!
		 */
		/*
		 * 得到dao实现类的名称
		 */
		String daoClassName = props.getProperty("cn.itcast.usermng.dao.UserDao");
		
		/*
		 * 通过反射来创建实现类的对象 
		 */
		try {
			Class clazz = Class.forName(daoClassName);
			return (UserDao)clazz.newInstance();
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}
}



时间类型

数据库类型与java中类型的对应关系:

DATE → java.sql.Date

TIME → java.sql.Time

TIMESTAMP → java.sql.Timestamp

领域对象(domain)中的所有属性不能出现java.sql包下的东西!即不能使用java.sql.Date;

ResultSet#getDate()返回的是java.sql.Date()

PreparedStatement#setDate(int, Date),其中第二个参数也是java.sql.Date

时间类型的转换:

java.util.Date  java.sql.Date、Time、Timestamp

把util的Date转换成毫秒值

使用毫秒值创建sql的Date、Time、Timestamp

java.sql.Date、Time、Timestamp  java.util.Date

这一步不需要处理了:因为java.sql.Date是java.util.Date;

java.util.Datedate = new java.util.Date();

longl = date.getTime();

java.sql.DatesqlDate = new java.sql.Date(l);


1 Java中的时间类型

java.sql包下给出三个与数据库相关的日期时间类型,分别是:

Date:表示日期,只有年月日,没有时分秒。会丢失时间;

Time:表示时间,只有时分秒,没有年月日。会丢失日期;

Timestamp:表示时间戳,有年月日时分秒,以及毫秒。

这三个类都是java.util.Date的子类。


2 时间类型相互转换

把数据库的三种时间类型赋给java.util.Date,基本不用转换,因为这是把子类对象给父类的引用,不需要转换。

java.sql.Date date = …

java.util.Date d = date;

java.sql.Time time = …

java.util.Date d = time;

java.sql.Timestamp timestamp = …

java.util.Date d = timestamp;

当需要把java.util.Date转换成数据库的三种时间类型时,这就不能直接赋值了,这需要使用数据库三种时间类型的构造器。java.sql包下的Date、Time、TimeStamp三个类的构造器都需要一个long类型的参数,表示毫秒值。创建这三个类型的对象,只需要有毫秒值即可。我们知道java.util.Date有getTime()方法可以获取毫秒值,那么这个转换也就不是什么问题了。

java.utl.Date d = new java.util.Date();

java.sql.Date date = newjava.sql.Date(d.getTime());//会丢失时分秒

Time time = new Time(d.getTime());//会丢失年月日

Timestamp timestamp = newTimestamp(d.getTime());


大数据

1 什么是大数据

所谓大数据,就是大的字节数据,或大的字符数据。标准SQL中提供了如下类型来保存大数据

标准SQL大数据类型

类型

长度

tinyblob

28--1B(256B)

blob

216-1B(64K)

mediumblob

224-1B(16M)

longblob

232-1B(4G)

tinyclob

28--1B(256B)

clob

216-1B(64K)

mediumclob

224-1B(16M)

longclob

232-1B(4G)

在mysql中没有提供tinyclob、clob、mediumclob、longclob四种类型

而是使用tinytext,text,mediumtext,longtext

代码

把mp3保存到数据库中!

com.mysql.jdbc.PacketTooBigException: Packet for query is too large (9802817 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.


在my.ini中设置,在[mysqld]下添加max_allowed_packet=10M,例如:

[mysqld]
max_allowed_packet=64M

/**
 * 大数据
 * @author cxf
 *
 */
public class Demo4 {
	/**
	 * 把mp3保存到数据库中。
	 * @throws SQLException 
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	@Test
	public void fun1() throws Exception {
		/*
		 * 1. 得到Connection
		 * 2. 给出sql模板,创建pstmt
		 * 3. 设置sql模板中的参数
		 * 4. 调用pstmt的executeUpdate()执行
		 */
		Connection con = JdbcUtils.getConnection();
		String sql = "insert into tab_bin values(?,?,?)";
		PreparedStatement pstmt = con.prepareStatement(sql);
		
		pstmt.setInt(1, 1);
		pstmt.setString(2, "流光飞舞.mp3");
		/**
		 * 需要得到Blob
		 * 1. 我们有的是文件,目标是Blob
		 * 2. 先把文件变成byte[]
		 * 3. 再使用byte[]创建Blob
		 */
		// 把文件转换成byte[]
		byte[] bytes = IOUtils.toByteArray(new FileInputStream("F:/流光飞舞.mp3"));
		// 使用byte[]创建Blob
		Blob blob = new SerialBlob(bytes);
		// 设置参数
		pstmt.setBlob(3, blob);
		
		pstmt.executeUpdate();
	}
	
	/**
	 * 从数据库读取mp3
	 * @throws SQLException 
	 */
	@Test
	public void fun2() throws Exception {
		/*
		 * 1. 创建Connection
		 */
		Connection con = JdbcUtils.getConnection();
		/*
		 * 2. 给出select语句模板,创建pstmt
		 */
		String sql = "select * from tab_bin";
		PreparedStatement pstmt = con.prepareStatement(sql);
		
		/*
		 * 3. pstmt执行查询,得到ResultSet
		 */
		ResultSet rs = pstmt.executeQuery();
		
		/*
		 * 4. 获取rs中名为data的列数据
		 */
		if(rs.next()) {
			Blob blob = rs.getBlob("data");
			/*
			 * 把Blob变成硬盘上的文件!
			 */
			/*
			 * 1. 通过Blob得到输入流对象
			 * 2. 自己创建输出流对象
			 * 3. 把输入流的数据写入到输出流中
			 */
			InputStream in = blob.getBinaryStream();
			OutputStream out = new FileOutputStream("c:/lgfw.mp3");
			IOUtils.copy(in, out);
		}
	}
}


批处理

MySQL的批处理也需要通过参数来打开:rewriteBatchedStatements=true


1 Statement批处理

批处理就是一批一批的处理,而不是一个一个的处理!

当你有10条SQL语句要执行时,一次向服务器发送一条SQL语句,这么做效率上很差!

处理的方案是使用批处理,即一次向服务器发送多条SQL语句,然后由服务器一次性处理。

批处理只针对更新(增、删、改)语句,批处理没有查询什么事儿!

可以多次调用Statement类的addBatch(Stringsql)方法,

把需要执行的所有SQL语句添加到一个“批”中,

然后调用Statement类的executeBatch()方法来执行当前“批”中的语句。

voidaddBatch(String sql):添加一条语句到“批”中;

int[]executeBatch():执行“批”中所有语句。返回值表示每条语句所影响的行数据;

voidclearBatch():清空“批”中的所有语句。

for(int i = 0; i < 10; i++) {
				String number = "S_10" + i;
				String name = "stu" + i;
				int age = 20 + i;
				String gender = i % 2 == 0 ? "male" : "female";
				String sql = "insert into stu values(&#39;" + number + "&#39;, &#39;" + name + "&#39;, " + age + ", &#39;" + gender + "&#39;)";
				stmt[内部有个集合,用来装载sql语句].addBatch(sql);
			}
			stmt.executeBatch[执行批,即一次把批中的所有sql语句发送给服务器]();


当执行了“批”之后,“批”中的SQL语句就会被清空!也就是说,连续两次调用executeBatch()相当于调用一次!因为第二次调用时,“批”中已经没有SQL语句了。

还可以在执行“批”之前,调用Statement的clearBatch()方法来清空“批”!


2PreparedStatement批处理

PreparedStatement的批处理有所不同,因为每个PreparedStatement对象都绑定一条SQL模板。

所以向PreparedStatement中添加的不是SQL语句,而是给“?”赋值。

/**
 * 批处理
 * @author cxf
 *
 */
public class Demo5 {
	/**
	 * pstmt对象内部有集合
	 * 1. 用循环疯狂向pstmt中添加sql参数,它自己有模板,使用一组参数与模板罚没可以匹配出一条sql语句
	 * 2. 调用它的执行批方法,完成向数据库发送!
	 * @throws SQLException 
	 */
	@Test
	public void fun5() throws SQLException {
		/*
		 * pstmt:
		 * > 添加参数到批中
		 * > 执行批!
		 */
		Connection con = JdbcUtils.getConnection();
		String sql = "INSERT INTO t_stu VALUES(?,?,?,?)";
		PreparedStatement pstmt = con.prepareStatement(sql);
		
		// 疯狂的添加参数
		for(int i = 0; i < 10000; i++) {
			pstmt.setInt(1, i+1);
			pstmt.setString(2, "stu_" + i);
			pstmt.setInt(3, i);
			pstmt.setString(4, i%2==0?"男":"女");
			
			pstmt.addBatch();//添加批!这一组参数就保存到集合中了。
		}
		long start = System.currentTimeMillis();
		pstmt.executeBatch();//执行批!
		long end = System.currentTimeMillis();
		
		System.out.println(end - start);//412764, 301
	}
}




Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn