JDBC(資料庫的驅動、連線、java程式操作資料庫、事務、隔離級別、連線池等)
java操作資料庫的思想:連上資料庫,傳送sql語句。在連上資料庫之前,要先用程式啟動資料庫,因此,可以通過反射載入類驅動(com.jdbc.mysql.Driver)。通過驅動管理類的靜態方法傳遞資料庫的url來獲取一個連線物件(connection)。有三個過載的方法,第一個user和password都追加在url後(類似於get傳參);第二種用逗號將user和passowrd隔開作為第二個和第三個引數;第三種通過配置檔案Properties(方便修改,不用編譯)。連線物件獲取到表示資料庫連線成功。
1.連線資料庫。獲得連線物件
public class Maintest { public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Properties p=new Properties(); p.load(new FileInputStream("E:\\IDEAJAVA\\Algorithm\\src\\test\\jdbc.properties")); Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/test",p); System.out.println(connection); } }
輸出結果
[email protected]
2.得到連線物件後就可以通過連線物件(connection)獲得傳送sql語句的物件(statement和PrepareStatement)。PrepareStatement相比Statement,可以進行預處理。就是先發送SQL語句,後傳送引數。傳送查詢語句用executeQuery方法,會返回一個Resultset物件。該物件封裝了查詢出的結果集;傳送其他語句可以用executeUpdate方法。該方法返回一個int型別的值,是影響了資料庫的條數。
建表前的資料庫:
mysql> use test Database changed mysql> show tables; Empty set (0.00 sec)
建表的語句:
Statement statement=connection.createStatement();//獲得傳送語句的物件 String createTable="create table student(" //建立表的sql語句 + "id int not null auto_increment primary key," + "name varchar(20)," + "sex varchar not default 'M'" + ");"; statement.executeUpdate(createTable);//執行sql語句
建表後在次查詢收據庫,表已建好。
mysql> show tables;
Empty set (0.00 sec)
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| student |
+----------------+
1 row in set (0.00 sec)
3.插入資料:運用Statement和PrepareStatem兩種類。
String insertData1="insert into student values(1,'zhangsan','M')";//statement的sql
String insertData2="insert into student values(?,?,?)";
PreparedStatement preparedStatement=connection.prepareStatement(insertData2);
statement.executeUpdate(insertData1);//執行插入資料
//設定引數
preparedStatement.setInt(1,2);
preparedStatement.setString(2,"lisi");
preparedStatement.setString(3,"M");
System.out.println(preparedStatement.executeUpdate());//返回影響的行數
結果返回1。再看資料庫中的內容,插入成功。
mysql> select * from student;
+----+----------+-----+
| id | name | sex |
+----+----------+-----+
| 1 | zhangsan | M |
| 2 | lisi | M |
+----+----------+-----+
2 rows in set (0.00 sec)
4.查詢:通過傳送sql的物件(Statement和PreparStatemente),用executeQuery方法傳送查詢的sql語句,返回Resultset物件。executeUpdate方法不能傳送查詢語句,可以傳送建表,修改表結構,插入資料,刪除資料,修改資料。
Statement statement=connection.createStatement();
String query="select * from student";
ResultSet resultSet=statement.executeQuery(query);//返回查詢結果
while(resultSet.next())
{
System.out.println("id:"+resultSet.getInt(1)+"\tname:"+resultSet.getString(2)+"\tsex:"+resultSet.getString(3));
}
System.out.println("--------------------------------------");
String querybyid="select * from student where id=?";
PreparedStatement preparedStatement=connection.prepareStatement(querybyid);
preparedStatement.setInt(1,1);//查詢id為1的學生的資訊。
ResultSet resultSet1=preparedStatement.executeQuery();
while(resultSet1.next())
{
System.out.println("id:"+resultSet1.getInt(1)+"\tname:"+resultSet1.getString(2)+"\tsex:"+resultSet1.getString(3));
}
查詢結果顯示:
id:1 name:zhangsan sex:M
id:2 name:lisi sex:M
--------------------------------------
id:1 name:zhangsan sex:M
5.批處理操作:通過addBatch方法向Statement物件中新增多個sql語句。再通過executeBatch方法執行每個SQL語句並返回每一條SQL語句執行後影響的行數。所以返回一個整型陣列。但是批處理中不能放查詢語句。
Statement statement=connection.createStatement();
statement.addBatch("insert into student values(3,\"luck\",\"F\");");
statement.addBatch("delete from student where id=1;");
System.out.println(Arrays.toString(statement.executeBatch()));
返回結果為1,1。資料庫查詢結果:
mysql> select * from student;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 2 | lisi | M |
| 3 | luck | F |
+----+------+-----+
2 rows in set (0.00 sec)
6.ResultSetMetaData類,該類封裝了一個查詢結果ResultSet的基本資訊,比如多少列、型別、建議名等。
Statement statement=connection.createStatement();
ResultSet resultSet=statement.executeQuery("select * from student");
ResultSetMetaData resultSetMetaData=resultSet.getMetaData();
for(int i=1;i<=resultSetMetaData.getColumnCount();i++)
{
System.out.print(resultSetMetaData.getColumnName(i)+"\t\t");
}
System.out.println();
while(resultSet.next())
{
System.out.println(resultSet.getInt(1)+"\t\t"+resultSet.getString(2)+"\t\t"+resultSet.getString(3));
}
查詢結果:
id name sex
2 lisi M
3 luck F
7.事務:jdbc本身不支援事務,jdbc只是對事務做了簡單的封裝。還是用了資料庫的事務。
事務四大特性:A(原子性)、C(一致性)、I(隔離性)、D(永續性)。
髒讀:事務A讀到了事務B修改單未提交的資料。
幻讀:事務A第一次讀到了符合條件的資料,事務B又添加了幾條符合條件的資料,事務A再次讀時,比第一次讀到的多。出現幻讀。
不可重複讀:事務A讀到資料後,事務B對資料進行修改,事務A再次讀資料發現兩次結果不一樣。
針對以上三個問題出現以下四種隔離級別:
序列化(Serializable):級別最高,對事務序列執行,耗資源最大
重複讀(repeatable read):保證了一個事務不會修改另一個事務已經讀到的資料,避免了髒讀和不可重複讀。是大多數系統預設的隔離級別。
提交讀(read commit):保證了一個事務不會讀到一個已經修改但是還未提交的資料。只避免了髒讀。
為提交讀(read uncommitted):一個事務中的修改即使沒有提交,其他事務也能查詢到。一下是對事務的操作:
connection.setAutoCommit(false);//開啟事務
try {
statement.executeUpdate("insert into student values(4,\"abc\",\"M\");");
statement.executeUpdate("delete from student where id=5;");//庫中沒有id=5的學生。出現異常
connection.commit();//未出現異常時提交
} catch (SQLException e) {
connection.rollback();//出現異常時撤回所有的操作
}finally {
connection.close();
}
因為出現異常,所有撤回所有的操作,因此在表中不能查到“abc”。將刪除的id改為2後繼續執行,這次不會出現異常,因此兩句都被執行並提交。
mysql> select * from student;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 3 | luck | F |
| 4 | abc | M |
+----+------+-----+
2 rows in set (0.00 sec)
msyql支援四種隔離級別,隔離級別的檢視與設定:
檢視全域性和會話事務的隔離級別
mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)
修改隔離級別:
mysql> set tx_isolation="serializable";
Query OK, 0 rows affected (0.11 sec)
mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+----------------+
| @@global.tx_isolation | @@tx_isolation |
+-----------------------+----------------+
| REPEATABLE-READ | SERIALIZABLE |
+-----------------------+----------------+
1 row in set (0.00 sec)
8.連線池:連線池記憶體放多個連線物件,當程式中需要用到時從中取出即可。不需要時,歸還給連線池。實現連線物件的複用。連線池就是用來管理連線物件的。連線池要實現DataSource介面,該介面中有一個getConnection方法獲得連線物件
c3p0連線池:下載c3p0的jar包,匯入jar包。在src目錄下加入c3p0.properties
配置檔案。
public class Maintest {
public static void main(String[] args) throws Exception {
DataSource ds=new ComboPooledDataSource();
for(int i=0;i<10;i++)
{
Connection con=ds.getConnection();
System.out.println(con);
con.close();//將連線物件歸還給連線池
}
}
}
配置檔案內容
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test
c3p0.user=root
c3p0.password=mysql
c3p0.maxPoolSize=10
c3p0.minPoolSize=3
Druid連線池:下載並匯入jar包。Druid相比於c3p0來說,更加靈活。既可以通過配置檔案來讀連線資料庫的資訊,也可以通過程式來設定。
public class Maintest {
public static void main(String[] args) throws Exception {
DruidDataSource ds=new DruidDataSource();
//通過程式設定
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
//通過配置檔案來設定。兩種方式
// ResourceBundle rs=ResourceBundle.getBundle("jdbc");
// ds.setUsername(rs.getString("user"));
// ds.setPassword(rs.getString("password"));
Properties properties=new Properties();
properties.load(new FileReader("E:\\IDEAJAVA\\Algorithm\\src\\jdbc.properties"));
ds.setUsername(properties.getProperty("user"));
ds.setPassword(properties.getProperty("password"));
ds.setInitialSize(3);
ds.setMaxActive(10);
Connection con=ds.getConnection();
System.out.println(con);
}
}
以上程式碼建立了Druid連線池,通過程式設定了mysql的驅動,以及mysql的url。通過兩種讀取配置檔案的方式來獲取使用者名稱和密碼,再將其設定到連線池物件中。最後再通過程式設定連線池的初始容量以及最大個數。通過連線池獲取物件,將物件輸出。