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。
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(); } } }
它是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();
工具代碼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");//配置文件路徑在src目錄下 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")); } }
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);
java.sql包下給出三個與數據庫相關的日期時間類型,分別是:
Date:表示日期,只有年月日,沒有時分秒。會丟失時間;
Time:表示時間,只有時分秒,沒有年月日。會丟失日期;
Timestamp:表示時間戳,有年月日時分秒,以及毫秒。
這三個類都是java.util.Date的子類。
把數據庫的三種時間類型賦給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. 自己創建
MySQL的批處理也需要通過參數來打開:rewriteBatchedStatements=true
批處理就是一批一批的處理,而不是一個一個的處理!
當你有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('" + number + "', '" + name + "', " + age + ", '" + gender + "')"; stmt[內部有個集合,用來裝載sql語句].addBatch(sql); } stmt.executeBatch[執行批,即一次把批中的所有sql語句發送給服務器]();
當執行了“批”之后,“批”中的SQL語句就會被清空!也就是說,連續兩次調用executeBatch()相當于調用一次!因為第二次調用時,“批”中已經沒有SQL語句了。
還可以在執行“批”之前,調用Statement的clearBatch()方法來清空“批”!
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 } }
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com