File notes/code/java/AdvancedProg.java added (mode: 100644) (index 0000000..af8273a) |
|
1 |
|
/* code/java/AdvancedProg.sql */ |
|
2 |
|
|
|
3 |
|
/* |
|
4 |
|
|
|
5 |
|
This is a long program, introducing: |
|
6 |
|
I. How to pass options when connecting to the database, |
|
7 |
|
II. How to create a table |
|
8 |
|
III. How to insert values |
|
9 |
|
IV. How to use prepared statements |
|
10 |
|
V. How to read backward and write in ResultSets |
|
11 |
|
|
|
12 |
|
If you want to run this program multiple times, you have to either: |
|
13 |
|
|
|
14 |
|
1. Comment first statement of II. Creating a table |
|
15 |
|
2. Change the name of the schema, from HW_DBPROG to whatever you want |
|
16 |
|
3. Drop the DVD table: connect to your database, and then enter |
|
17 |
|
USE HW_DBPROG; |
|
18 |
|
DROP TABLE DVD; |
|
19 |
|
Or do it from within your program! |
|
20 |
|
|
|
21 |
|
If you use option 1, you will keep inserting tuples in your table: cleaning it with |
|
22 |
|
DELETE FROM DVD; |
|
23 |
|
can help. You can do it from within the program! |
|
24 |
|
*/ |
|
25 |
|
|
|
26 |
|
import java.sql.*; |
|
27 |
|
|
|
28 |
|
public class AdvancedProg { |
|
29 |
|
public static void main(String[] args) { |
|
30 |
|
try ( |
|
31 |
|
|
|
32 |
|
/* |
|
33 |
|
* I. Passing options to the dababse |
|
34 |
|
*/ |
|
35 |
|
|
|
36 |
|
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/HW_DBPROG" |
|
37 |
|
+ "?user=testuser" |
|
38 |
|
+ "&password=password" |
|
39 |
|
+ "&allowMultiQueries=true" |
|
40 |
|
+ "&createDatabaseIfNotExist=true" |
|
41 |
|
+ "&useSSL=true"); |
|
42 |
|
|
|
43 |
|
// Read about other options at |
|
44 |
|
// https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html |
|
45 |
|
// https://jdbc.postgresql.org/documentation/head/connect.html |
|
46 |
|
|
|
47 |
|
Statement stmt = conn.createStatement(); |
|
48 |
|
) { |
|
49 |
|
|
|
50 |
|
/* |
|
51 |
|
* II. Creating a table |
|
52 |
|
*/ |
|
53 |
|
|
|
54 |
|
stmt.execute("CREATE TABLE DVD (" + |
|
55 |
|
"Title CHAR(25) PRIMARY KEY, " + |
|
56 |
|
"Minutes INTEGER, " + |
|
57 |
|
"Price DOUBLE)"); |
|
58 |
|
|
|
59 |
|
/* If we were to execute |
|
60 |
|
* SHOW TABLES |
|
61 |
|
* directly in the MySQL interpreter, this would display at the screen |
|
62 |
|
* |
|
63 |
|
* +--------------------------+ |
|
64 |
|
* | Tables_in_HW_NewDataBase | |
|
65 |
|
* +--------------------------+ |
|
66 |
|
* | DVD | |
|
67 |
|
* +--------------------------+ |
|
68 |
|
* |
|
69 |
|
* But here, to access this information, we will use the connection's metadata. |
|
70 |
|
*/ |
|
71 |
|
|
|
72 |
|
DatabaseMetaData md = conn.getMetaData(); |
|
73 |
|
// DatabaseMetaData is a class used to get information about the database: the driver, the user, the versions, etc. |
|
74 |
|
|
|
75 |
|
ResultSet rs = md.getTables(null, null, "%", null); |
|
76 |
|
|
|
77 |
|
/* |
|
78 |
|
* You can read at |
|
79 |
|
* https://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getTables(java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String[]) |
|
80 |
|
* the full specification of this method. |
|
81 |
|
* All you need to know, for now, is that the third parameter is |
|
82 |
|
* String tableNamePattern, |
|
83 |
|
* i.e., what must match the table name as it is stored in the database |
|
84 |
|
* Here, by using the wildcard "%", we select all the table names. |
|
85 |
|
* We can then iterate over the ResultSet as usual: |
|
86 |
|
*/ |
|
87 |
|
|
|
88 |
|
while (rs.next()) { |
|
89 |
|
System.out.println(rs.getString(3)); // In the ResultSet returned by getTables, 3 is the TABLE_NAME. |
|
90 |
|
} |
|
91 |
|
|
|
92 |
|
/* |
|
93 |
|
* III. Inserting values |
|
94 |
|
*/ |
|
95 |
|
|
|
96 |
|
String sqlStatement = "INSERT INTO DVD VALUES ('Gone With The Wind', 221, 3);"; |
|
97 |
|
int rowsAffected = stmt.executeUpdate(sqlStatement); |
|
98 |
|
System.out.print(sqlStatement + " changed " + rowsAffected + " row(s).\n"); |
|
99 |
|
|
|
100 |
|
|
|
101 |
|
/* |
|
102 |
|
* Batch Insertion |
|
103 |
|
*/ |
|
104 |
|
|
|
105 |
|
String insert1 = "INSERT INTO DVD VALUES ('Aa', 129, 0.2)"; |
|
106 |
|
String insert2 = "INSERT INTO DVD VALUES ('Bb', 129, 0.2)"; |
|
107 |
|
String insert3 = "INSERT INTO DVD VALUES ('Cc', 129, 0.2)"; |
|
108 |
|
String insert4 = "INSERT INTO DVD VALUES ('DD', 129, 0.2)"; |
|
109 |
|
|
|
110 |
|
// Method 1: Using executeUpdate, if the option allowMultiQueries=true was passed in the url given to getConnection and your DBMS supports it. |
|
111 |
|
stmt.executeUpdate(insert1 + ";" + insert2); |
|
112 |
|
|
|
113 |
|
// Method 2: Using the addBatch and executeBatch methods |
|
114 |
|
stmt.addBatch(insert3); |
|
115 |
|
stmt.addBatch(insert4); |
|
116 |
|
stmt.executeBatch(); |
|
117 |
|
|
|
118 |
|
|
|
119 |
|
/* |
|
120 |
|
* IV. Prepared Statements |
|
121 |
|
*/ |
|
122 |
|
|
|
123 |
|
// Example 1 |
|
124 |
|
sqlStatement = "SELECT title FROM DVD WHERE Price <= ?"; // We have a string with an empty slot, represented by "?". |
|
125 |
|
PreparedStatement ps = conn.prepareStatement(sqlStatement); // We create a PreparedStatement object, using that string with an empty slot. |
|
126 |
|
float maxprice = 0.5f; |
|
127 |
|
ps.setFloat(1, maxprice); // This statement says "Fill the first slot with the value of maxprice". |
|
128 |
|
ResultSet result = ps.executeQuery(); // And then we can execute the query, and display the results: |
|
129 |
|
|
|
130 |
|
System.out.printf("For %.2f you can get:\n", maxprice); |
|
131 |
|
|
|
132 |
|
while(result.next()){ |
|
133 |
|
System.out.printf("\t %s \n", result.getString(1)); |
|
134 |
|
} |
|
135 |
|
|
|
136 |
|
// Example 2 |
|
137 |
|
sqlStatement = "INSERT INTO DVD VALUES (?, ?, ?)"; // Now, our string has 3 empty slots, and it is an INSERT statement. |
|
138 |
|
PreparedStatement preparedStatement = conn.prepareStatement(sqlStatement); |
|
139 |
|
|
|
140 |
|
preparedStatement.setString(1, "The Great Dictator"); |
|
141 |
|
preparedStatement.setInt(2, 124); |
|
142 |
|
preparedStatement.setFloat(3, 5.4f); |
|
143 |
|
|
|
144 |
|
rowsAffected = preparedStatement.executeUpdate(); // You can check "by hand" that this statement was correctly executed. |
|
145 |
|
System.out.print(preparedStatement.toString() + " changed "+ rowsAffected + " row(s).\n"); |
|
146 |
|
|
|
147 |
|
|
|
148 |
|
// If we try to mess things up, i.e., provide wrong datatypes: |
|
149 |
|
preparedStatement.setString(1, "The Great Dictator"); |
|
150 |
|
preparedStatement.setString(2, "The Great Dictator"); |
|
151 |
|
preparedStatement.setString(3, "The Great Dictator"); |
|
152 |
|
|
|
153 |
|
// Java compiler will be ok, but we'll have an error at execution time when executing the query. You can uncomment the line below to see for yourself. |
|
154 |
|
//rowsAffected = preparedStatement.executeUpdate(); |
|
155 |
|
|
|
156 |
|
// Of course, we can use prepared statement inside loops. |
|
157 |
|
for (int i = 1; i < 5; i++) { |
|
158 |
|
preparedStatement.setString(1, "Saw " + i); |
|
159 |
|
preparedStatement.setInt(2, 100); |
|
160 |
|
preparedStatement.setFloat(3, .5f); |
|
161 |
|
preparedStatement.executeUpdate(); |
|
162 |
|
} |
|
163 |
|
|
|
164 |
|
/* |
|
165 |
|
* V. Reading backward and writing in ResultSets |
|
166 |
|
*/ |
|
167 |
|
|
|
168 |
|
// To read backward and write in ResultSets, you need to have a statement with certain options: |
|
169 |
|
|
|
170 |
|
Statement stmtNew = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); |
|
171 |
|
|
|
172 |
|
/* |
|
173 |
|
* Those options change two things about the ResultSet we obtain using this statement |
|
174 |
|
* |
|
175 |
|
* The first argument is the scrolling level: |
|
176 |
|
* TYPE_FORWARD_ONLY = default. |
|
177 |
|
* TYPE_SCROLL_INSENSITIVE = can scroll, but updates don't impact result set. |
|
178 |
|
* TYPE_SCROLL_SENSITIVE = can scroll, update impact result set. |
|
179 |
|
* |
|
180 |
|
* The second argument is the concurrency level: |
|
181 |
|
* CONCUR_READ_ONLY: default. |
|
182 |
|
* CONCUR_UPDATABLE: we can change the database without issuing SQL statement. |
|
183 |
|
*/ |
|
184 |
|
|
|
185 |
|
/* |
|
186 |
|
* Reading backward |
|
187 |
|
*/ |
|
188 |
|
|
|
189 |
|
sqlStatement = "SELECT title FROM DVD WHERE Price < 1;"; |
|
190 |
|
result = stmtNew.executeQuery(sqlStatement); |
|
191 |
|
|
|
192 |
|
System.out.println("For $1, you can get:"); |
|
193 |
|
|
|
194 |
|
if (result.last()) { // We can jump to the end of the ResultSet |
|
195 |
|
System.out.print(result.getString("Title") + " "); |
|
196 |
|
} |
|
197 |
|
|
|
198 |
|
System.out.print("and also, (in reverse order)"); |
|
199 |
|
|
|
200 |
|
while (result.previous()) { // Now we can scroll back! |
|
201 |
|
System.out.print(result.getString("Title") + " "); |
|
202 |
|
} |
|
203 |
|
|
|
204 |
|
/* |
|
205 |
|
* Other methods to navigate in ResultSet: |
|
206 |
|
* first() |
|
207 |
|
* last() |
|
208 |
|
* next() |
|
209 |
|
* previous() |
|
210 |
|
* relative(x) : move cursor x times (positive = forward, negative = backward) |
|
211 |
|
* absolute(x): move to the row number x. 1 is the first. |
|
212 |
|
*/ |
|
213 |
|
|
|
214 |
|
/* |
|
215 |
|
* Changing the values |
|
216 |
|
*/ |
|
217 |
|
|
|
218 |
|
System.out.print("\n\nLet us apply a 50% discount. Currently, the prices are:\n"); |
|
219 |
|
|
|
220 |
|
sqlStatement = "SELECT title, price FROM DVD;"; |
|
221 |
|
result = stmtNew.executeQuery(sqlStatement); |
|
222 |
|
while (result.next()) { |
|
223 |
|
System.out.printf("%20s \t $%3.2f\n", result.getString("title") , result.getDouble("price")); |
|
224 |
|
} |
|
225 |
|
|
|
226 |
|
|
|
227 |
|
result.absolute(0); // We need to scroll back! |
|
228 |
|
|
|
229 |
|
while (result.next()) { |
|
230 |
|
double current = result.getDouble("price"); |
|
231 |
|
result.updateDouble("price", (current * 0.5)); |
|
232 |
|
result.updateRow(); |
|
233 |
|
} |
|
234 |
|
System.out.print("\n\nAfter update, the prices are:\n"); |
|
235 |
|
|
|
236 |
|
result.absolute(0); // We need to scroll back! |
|
237 |
|
|
|
238 |
|
while (result.next()) { |
|
239 |
|
System.out.printf("%20s \t $%3.2f\n", result.getString("title") , result.getDouble("price")); |
|
240 |
|
} |
|
241 |
|
|
|
242 |
|
|
|
243 |
|
conn.close(); |
|
244 |
|
} catch (SQLException ex) { |
|
245 |
|
ex.printStackTrace(); |
|
246 |
|
} |
|
247 |
|
} |
|
248 |
|
} |
File notes/lectures_notes.md changed (mode: 100644) (index 5b31f3e..6153e9e) |
... |
... |
How things can go wrong: |
586 |
586 |
How things can go wrong: |
How things can go wrong: |
587 |
587 |
|
|
588 |
588 |
- Deleting tuples inadvertently (meta) |
- Deleting tuples inadvertently (meta) |
589 |
|
- Delecing tuples that are referenced (a., b., c.) |
|
|
589 |
|
- Delecing tuples that are referenced (1., 2., 3.) |
590 |
590 |
|
|
591 |
591 |
#### Update (a.k.a. modify) |
#### Update (a.k.a. modify) |
592 |
592 |
|
|
|
... |
... |
How things can go wrong: |
596 |
596 |
|
|
597 |
597 |
- Duplicate value for the primary key (1.) |
- Duplicate value for the primary key (1.) |
598 |
598 |
- `NULL` for the primary key (1.) |
- `NULL` for the primary key (1.) |
599 |
|
- Change value that are referenced (a., b., c.) |
|
|
599 |
|
- Change value that are referenced (1., 2., 3.) |
600 |
600 |
- Change foreign key to a non-existing value (1.) |
- Change foreign key to a non-existing value (1.) |
601 |
601 |
|
|
602 |
602 |
|
|
|
... |
... |
There are 14 different types of diagrams, divided between two categories: struct |
3831 |
3831 |
|
|
3832 |
3832 |
 |
 |
3833 |
3833 |
|
|
|
3834 |
|
(Source: <https://commons.wikimedia.org/wiki/File:UML_diagrams_overview.svg>) |
|
3835 |
|
|
3834 |
3836 |
#### Structural UML diagrams |
#### Structural UML diagrams |
3835 |
3837 |
|
|
3836 |
3838 |
They describe structural, or static, relationships between objects, softwares. |
They describe structural, or static, relationships between objects, softwares. |
|
... |
... |
Solution +.# |
4206 |
4208 |
: For a weak entity attribute, it is the attribute that can uniquely identify weak entites that are related to the same owner entity. |
: For a weak entity attribute, it is the attribute that can uniquely identify weak entites that are related to the same owner entity. |
4207 |
4209 |
|
|
4208 |
4210 |
Solution +.# |
Solution +.# |
|
4211 |
|
~ |
4209 |
4212 |
|
|
4210 |
4213 |
Entity 1 | Cardinality Ratio | Entity 2 | Explanation | |
Entity 1 | Cardinality Ratio | Entity 2 | Explanation | |
4211 |
4214 |
| --- | :---: | --- | --------| |
| --- | :---: | --- | --------| |
|
... |
... |
Problem (Design for your Professor) +.#designforprof |
4368 |
4371 |
~ |
~ |
4369 |
4372 |
Your professor designed the following relational model at some point in his career, to help him organizing his exams and the students grades: |
Your professor designed the following relational model at some point in his career, to help him organizing his exams and the students grades: |
4370 |
4373 |
|
|
|
4374 |
|
<!-- bug with table --> |
4371 |
4375 |
Table Name and Attributes | Example of Value | |
Table Name and Attributes | Example of Value | |
4372 |
4376 |
--- | --- |
--- | --- |
4373 |
4377 |
EXAM(Number, Date, Course) | < 1, '2018-02-14', 'CSCI3410'> |
EXAM(Number, Date, Course) | < 1, '2018-02-14', 'CSCI3410'> |
4374 |
4378 |
PROBLEM(Statement, Points, Length, Exam) | < 'Your professor designed…', 10, '00:10:00', 1> |
PROBLEM(Statement, Points, Length, Exam) | < 'Your professor designed…', 10, '00:10:00', 1> |
4375 |
4379 |
STUDENT\_GRADE(Login, Exam, Grade) | < 'aalyx', 1, 83> |
STUDENT\_GRADE(Login, Exam, Grade) | < 'aalyx', 1, 83> |
4376 |
4380 |
|
|
4377 |
|
where `EXAM.Number`, `PROBLEM.Statement`, `STUDENT_GRADE.Login` and `STUDENT_GRADE.Exam` are primary key, and where `STUDENT_GRADE.Exam` and `PROBLEM.Exam` both refer to `EXAM.Number`. |
|
|
4381 |
|
where `EXAM.Number`, `PROBLEM.Statement`, `STUDENT_GRADE.Login` and `STUDENT_GRADE.Exam` are primary key, and where `STUDENT_GRADE.Exam` and `PROBLEM.Exam` both refer to `EXAM.Number`. |
4378 |
4382 |
|
|
4379 |
|
The idea was to have |
|
|
4383 |
|
The idea was to have |
4380 |
4384 |
|
|
4381 |
|
- The `EXAM` table storing information about exams, |
|
4382 |
|
- One entry per problem in the PROBLEM table, and to associate every problem to an exam, |
|
4383 |
|
- The grade of one student for one particular exam stored in the `STUDENT\_GRADE` table. |
|
4384 |
|
|
|
4385 |
|
Unfortunately, this design turned out to be terrible. |
|
4386 |
|
Describe at least one common and interesting situation where this model would fail to fulfill its purpose, and propose a way to correct the particular problem you identified. |
|
4387 |
|
|
|
4388 |
|
<!-- Bug with table --> |
|
|
4385 |
|
- The `EXAM` table storing information about exams, |
|
4386 |
|
- One entry per problem in the PROBLEM table, and to associate every problem to an exam, |
|
4387 |
|
- The grade of one student for one particular exam stored in the `STUDENT\_GRADE` table. |
4389 |
4388 |
|
|
|
4389 |
|
Unfortunately, this design turned out to be terrible. |
|
4390 |
|
Describe at least one common and interesting situation where this model would fail to fulfill its purpose, and propose a way to correct the particular problem you identified. |
4390 |
4391 |
|
|
4391 |
4392 |
--- |
--- |
4392 |
4393 |
|
|
|
... |
... |
Problem (ER diagram for Car Insurance) +.#car-insurance |
4434 |
4435 |
|
|
4435 |
4436 |
--- |
--- |
4436 |
4437 |
|
|
4437 |
|
Problem +.#ERtoREL |
|
4438 |
|
~ \ |
|
|
4438 |
|
Problem (ER-to-Relation mapping for Car Insurance) +.#ERtoREL |
|
4439 |
|
~ |
4439 |
4440 |
|
|
4440 |
4441 |
Apply the ER-to-Relation mapping to your ER diagram from the previous problem. |
Apply the ER-to-Relation mapping to your ER diagram from the previous problem. |
4441 |
4442 |
|
|
4442 |
4443 |
--- |
--- |
4443 |
4444 |
|
|
4444 |
|
Problem +.# |
|
4445 |
|
~ \ |
|
|
4445 |
|
Problem (ER-to-Relation mapping for Country)+ .# |
|
4446 |
|
~ |
4446 |
4447 |
|
|
4447 |
|
Consider the following E.R. schema: |
|
|
4448 |
|
Consider the following E.R. schema: |
4448 |
4449 |
|
|
4449 |
|
 |
|
4450 |
|
\ |
|
|
4450 |
|
 |
|
4451 |
|
\ |
4451 |
4452 |
|
|
4452 |
|
where |
|
|
4453 |
|
where |
4453 |
4454 |
|
|
4454 |
|
- "W\_IN" stands for "WRITTEN\_IN", and |
|
4455 |
|
- "B\_W\_F" stands for "BORROWS\_WORDS\_FROM". |
|
|
4455 |
|
- "W\_IN" stands for "WRITTEN\_IN", and |
|
4456 |
|
- "B\_W\_F" stands for "BORROWS\_WORDS\_FROM". |
4456 |
4457 |
|
|
4457 |
|
For this relationship, on the left-hand side is the language that borrows a word, and on the right-hand side is the language that provides the loanword. |
|
|
4458 |
|
For this relationship, on the left-hand side is the language that borrows a word, and on the right-hand side is the language that provides the loanword. |
4458 |
4459 |
|
|
4459 |
|
Map that E.R. diagram to a relational database schema. |
|
|
4460 |
|
Map that E.R. diagram to a relational database schema. |
4460 |
4461 |
|
|
4461 |
4462 |
--- |
--- |
4462 |
4463 |
|
|
|
... |
... |
Based on the given primary key, is this relation in 1NF, 2NF, or 3NF? Why or why |
4480 |
4481 |
|
|
4481 |
4482 |
--- |
--- |
4482 |
4483 |
|
|
4483 |
|
Problem +.# |
|
|
4484 |
|
Problem (Normalizing the FLIGHT relation) +.# |
4484 |
4485 |
~ |
~ |
4485 |
4486 |
|
|
4486 |
4487 |
Consider the following relation: |
Consider the following relation: |
|
... |
... |
Problem +.# |
4499 |
4500 |
|
|
4500 |
4501 |
--- |
--- |
4501 |
4502 |
|
|
4502 |
|
Problem +.#bike |
|
|
4503 |
|
Problem (From business statement to dependencies) +.#bike |
4503 |
4504 |
~ |
~ |
4504 |
4505 |
|
|
4505 |
4506 |
This problem asks you to convert business statements into dependencies. |
This problem asks you to convert business statements into dependencies. |
|
... |
... |
Problem +.#bike |
4523 |
4524 |
|
|
4524 |
4525 |
--- |
--- |
4525 |
4526 |
|
|
4526 |
|
Problem +.# |
|
|
4527 |
|
Problem (Normalization)+.# |
4527 |
4528 |
~ |
~ |
4528 |
4529 |
|
|
4529 |
4530 |
<!-- bug with table --> |
<!-- bug with table --> |
4530 |
|
|
|
4531 |
4531 |
Consider the relations $R$ and $T$ below, and their functional dependencies (on top of the one induced by the primary keys): |
Consider the relations $R$ and $T$ below, and their functional dependencies (on top of the one induced by the primary keys): |
4532 |
4532 |
|
|
4533 |
4533 |
| |
| |
|
... |
... |
import java.sql.*; |
4908 |
4908 |
public class FirstProg { |
public class FirstProg { |
4909 |
4909 |
public static void main(String[] args) { |
public static void main(String[] args) { |
4910 |
4910 |
try ( |
try ( |
4911 |
|
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/HW_ebookshop", "testuser","password"); |
|
|
4911 |
|
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/HW_EBOOKSHOP", "testuser","password"); |
4912 |
4912 |
Statement stmt = conn.createStatement(); |
Statement stmt = conn.createStatement(); |
4913 |
4913 |
) { |
) { |
4914 |
4914 |
String strSelect = "SELECT title, price, qty FROM books WHERE qty > 40"; |
String strSelect = "SELECT title, price, qty FROM books WHERE qty > 40"; |
|
... |
... |
public class FirstProg { |
4942 |
4942 |
A couple of comments: |
A couple of comments: |
4943 |
4943 |
|
|
4944 |
4944 |
- `java.sql.*` contains the classes `Connection`, `Statement`, `ResultSet`, `ResultSetMetadata`. |
- `java.sql.*` contains the classes `Connection`, `Statement`, `ResultSet`, `ResultSetMetadata`. |
4945 |
|
- In the string `"jdbc:mysql://localhost:3306/HW_ebookshop"`, `jdbc` is the protocol, `mysql` is the subprotocol, `localhost` is the url of the database, `3306` is the port, and `HW_ebookshop` is the schema (that needs to already exist in this case). |
|
|
4945 |
|
- In the string `"jdbc:mysql://localhost:3306/HW_EBOOKSHOP"`, `jdbc` is the protocol, `mysql` is the subprotocol, `localhost` is the url of the database, `3306` is the port, and `HW_EBOOKSHOP` is the schema (that needs to already exist in this case). |
4946 |
4946 |
- Note that `strSelect` doesn't end with `;` (it could, but doesn't have to). |
- Note that `strSelect` doesn't end with `;` (it could, but doesn't have to). |
4947 |
4947 |
- `next()` returns true if there is something left in the set of result, and move to the next line if it is the case. It is close to the code we would use to read from a file. |
- `next()` returns true if there is something left in the set of result, and move to the next line if it is the case. It is close to the code we would use to read from a file. |
4948 |
4948 |
- We could use `1`, `2`, and `3` instead of `"title"`, `"price"` and `"qty"` in the `while` loop: `getString`, `getDouble` and `getInt` also take integers, corresponding to the position of the attribute in the result set. |
- We could use `1`, `2`, and `3` instead of `"title"`, `"price"` and `"qty"` in the `while` loop: `getString`, `getDouble` and `getInt` also take integers, corresponding to the position of the attribute in the result set. |
|
... |
... |
A couple of comments: |
4950 |
4950 |
|
|
4951 |
4951 |
### The database |
### The database |
4952 |
4952 |
|
|
4953 |
|
~~~{.sqlmysql .numberLines} |
|
4954 |
|
CREATE DATABASE HW_ebookshop; |
|
4955 |
|
|
|
4956 |
|
USE HW_ebookshop; |
|
4957 |
|
|
|
4958 |
|
CREATE TABLE books ( |
|
4959 |
|
id int PRIMARY KEY, |
|
4960 |
|
title varchar(50), |
|
4961 |
|
author varchar(50), |
|
4962 |
|
price float, |
|
4963 |
|
qty int |
|
4964 |
|
); |
|
4965 |
|
|
|
4966 |
|
INSERT INTO books VALUES (1001, 'Java for dummies', 'Tan Ah Teck', 11.11, 11); |
|
4967 |
|
INSERT INTO books VALUES (1002, 'More Java for dummies', 'Tan Ah Teck', 22.22, 22); |
|
4968 |
|
INSERT INTO books VALUES (1003, 'More Java for more dummies', 'Mohammad Ali', 33.33, 33); |
|
4969 |
|
INSERT INTO books VALUES (1004, 'A Cup of Java', 'Kumar', 44.44, 44); |
|
4970 |
|
INSERT INTO books VALUES (1005, 'A Teaspoon of Java', 'Kevin Jones', 55.55, 55); |
|
4971 |
|
~~~ |
|
|
4953 |
|
```{.sqlmysql .numberLines include=code/sql/HW_EBOOKSHOP.sql} |
|
4954 |
|
``` |
4972 |
4955 |
|
|
4973 |
4956 |
|
|
4974 |
4957 |
~~~{.plain .numberlines} |
~~~{.plain .numberlines} |
4975 |
|
MariaDB [HW_ebookshop]> SELECT * FROM books; |
|
|
4958 |
|
MariaDB [HW_EBOOKSHOP]> SELECT * FROM books; |
4976 |
4959 |
+------+----------------------------+--------------+-------+------+ |
+------+----------------------------+--------------+-------+------+ |
4977 |
4960 |
| id | title | author | price | qty | |
| id | title | author | price | qty | |
4978 |
4961 |
+------+----------------------------+--------------+-------+------+ |
+------+----------------------------+--------------+-------+------+ |
|
... |
... |
conn.close(); |
5035 |
5018 |
|
|
5036 |
5019 |
You would obtain: |
You would obtain: |
5037 |
5020 |
|
|
5038 |
|
~~~{.plain .numberLines}} |
|
|
5021 |
|
~~~{.plain .numberLines} |
5039 |
5022 |
The records selected are: |
The records selected are: |
5040 |
5023 |
1001 id, Java for dummies title, Tan Ah Teck author, 11.11 price, 11 qty |
1001 id, Java for dummies title, Tan Ah Teck author, 11.11 price, 11 qty |
5041 |
5024 |
1002 id, More Java for dummies title, Tan Ah Teck author, 22.22 price, 22 qty |
1002 id, More Java for dummies title, Tan Ah Teck author, 22.22 price, 22 qty |
|
... |
... |
You can pass options when creating Statement objects to be able to read it both |
5128 |
5111 |
## Exercises {-} |
## Exercises {-} |
5129 |
5112 |
|
|
5130 |
5113 |
Exercise +.# |
Exercise +.# |
5131 |
|
~ What are the technologies that makes it possible for a Java application to communicate with a DBMS? |
|
5132 |
5114 |
|
|
5133 |
|
Exercise +.# |
|
5134 |
|
~ What JDBC method do you call to get a connection to a database? |
|
|
5115 |
|
: What are the technologies that makes it possible for a Java application to communicate with a DBMS? |
5135 |
5116 |
|
|
5136 |
5117 |
Exercise +.# |
Exercise +.# |
5137 |
|
~ Briefly explain what the `next()` method from the `ResultSet` class does, and give its return type. |
|
5138 |
5118 |
|
|
5139 |
|
Exercise +.# |
|
5140 |
|
~ How do you submit a `SELECT` statement to the DBMS? |
|
|
5119 |
|
: What JDBC method do you call to get a connection to a database? |
5141 |
5120 |
|
|
5142 |
5121 |
Exercise +.# |
Exercise +.# |
5143 |
|
~ Where is a `ResultSet` object's cursor initially pointing? How do you move the cursor forward in the result set? |
|
5144 |
5122 |
|
|
5145 |
|
Exercise +.# |
|
5146 |
|
~ Give three navigation methods provided by `ResultSet`. |
|
|
5123 |
|
: Briefly explain what the `next()` method from the `ResultSet` class does, and give its return type. |
5147 |
5124 |
|
|
5148 |
5125 |
Exercise +.# |
Exercise +.# |
5149 |
|
~ Explain this JDBC URL format: |
|
5150 |
5126 |
|
|
5151 |
|
~~~{.java .numberLines} |
|
5152 |
|
jdbc:mysql://localhost:3306/HW_NewDB?createDatabaseIfNotExist=true&useSSL=true |
|
5153 |
|
~~~ |
|
|
5127 |
|
: How do you submit a `SELECT` statement to the DBMS? |
5154 |
5128 |
|
|
5155 |
5129 |
Exercise +.# |
Exercise +.# |
5156 |
|
~ In what class is the `getColumnName` method? |
|
5157 |
5130 |
|
|
5158 |
|
Exercise +.# |
|
5159 |
|
~ What is a prepared statement? |
|
|
5131 |
|
: Where is a `ResultSet` object's cursor initially pointing? How do you move the cursor forward in the result set? |
5160 |
5132 |
|
|
5161 |
5133 |
Exercise +.# |
Exercise +.# |
5162 |
|
~ In the code below, there are five errors between line 11 and line 30. They are *not* subtle Java errors (like misspelling a key word) and do not come from the DBMS (so you should assume that the password is correct, that the database exists, etc.). For each error, highlight it precisely and give a short explanation. |
|
5163 |
5134 |
|
|
5164 |
|
~~~{.java .numberLines} |
|
5165 |
|
import java.sql.*; |
|
|
5135 |
|
: Give three navigation methods provided by `ResultSet`. |
5166 |
5136 |
|
|
5167 |
|
public class MyProg{ |
|
5168 |
|
public static void main(String[] args) { |
|
5169 |
|
try ( |
|
5170 |
|
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/" |
|
5171 |
|
+"HW_TestDB?user=testuser&password=password"); |
|
5172 |
|
Statement stmt = conn.createStatement(); |
|
5173 |
|
) { |
|
|
5137 |
|
Exercise +.# |
|
5138 |
|
~ |
5174 |
5139 |
|
|
5175 |
|
/* Errors after this point.*/ |
|
|
5140 |
|
Explain this JDBC URL format: |
5176 |
5141 |
|
|
5177 |
|
String strSelect = "SELECT title FROM disks WHERE qty > 40;"; |
|
5178 |
|
ResultSet rset = stmt.executeUpdate(strSelect); |
|
|
5142 |
|
~~~{.java .numberLines} |
|
5143 |
|
jdbc:mysql://localhost:3306/HW_NewDB?createDatabaseIfNotExist=true&useSSL=true |
|
5144 |
|
~~~ |
5179 |
5145 |
|
|
5180 |
|
System.out.println("The records selected are: (listed last first):"); |
|
5181 |
|
rset.last(); |
|
|
5146 |
|
Exercise +.# |
5182 |
5147 |
|
|
5183 |
|
while(rset.previous()) { |
|
5184 |
|
String title = rset.getDouble("title"); |
|
5185 |
|
System.out.println(title + "\n"); |
|
5186 |
|
} |
|
|
5148 |
|
: In what class is the `getColumnName` method? |
5187 |
5149 |
|
|
5188 |
|
String sss = "SELECT title FROM disks WHERE Price <= ?"; |
|
5189 |
|
PreparedStatement ps = conn.prepareStatement(sss); |
|
5190 |
|
ResultSet result = ps.executeQuery(); |
|
|
5150 |
|
Exercise +.# |
5191 |
5151 |
|
|
5192 |
|
conn.close(); |
|
|
5152 |
|
: What is a prepared statement? |
5193 |
5153 |
|
|
5194 |
|
/* Errors before this point.*/ |
|
|
5154 |
|
Exercise +.# |
|
5155 |
|
~ |
5195 |
5156 |
|
|
5196 |
|
} catch(SQLException ex) { |
|
5197 |
|
ex.printStackTrace(); |
|
5198 |
|
} |
|
5199 |
|
} |
|
5200 |
|
} |
|
5201 |
|
~~~ |
|
|
5157 |
|
In the code below, there are five errors between line 13 and line 32. |
|
5158 |
|
They are *not* subtle Java errors (like misspelling a key word) and do not come from the DBMS (so you should assume that the password is correct, that the database exists, etc.). |
|
5159 |
|
For each error, highlight it precisely and give a short explanation. |
|
5160 |
|
|
|
5161 |
|
```{.java .numberLines include=code/java/ProgWithErrors.java} |
|
5162 |
|
``` |
5202 |
5163 |
|
|
5203 |
5164 |
Exercise +.# |
Exercise +.# |
5204 |
|
~ Write a small program that determine whenever the `null` value from Java is equal to the `NULL` value in your DBMS. |
|
|
5165 |
|
|
|
5166 |
|
: Write a small program that determine whenever the `null` value from Java is equal to the `NULL` value in your DBMS. |
5205 |
5167 |
|
|
5206 |
5168 |
## Solution to Exercises {-} |
## Solution to Exercises {-} |
5207 |
5169 |
|
|
|
... |
... |
Solution +.# |
5245 |
5207 |
Solution +.# |
Solution +.# |
5246 |
5208 |
|
|
5247 |
5209 |
: List errors in program TO DO. |
: List errors in program TO DO. |
5248 |
|
|
|
5249 |
5210 |
<!-- |
<!-- |
5250 |
5211 |
% |
% |
5251 |
5212 |
%METADATA |
%METADATA |
|
... |
... |
Solution +.# |
5302 |
5263 |
## Problems |
## Problems |
5303 |
5264 |
|
|
5304 |
5265 |
- If you experience troubles, <https://www.ntu.edu.sg/home/ehchua/programming/howto/ErrorMessages.html#JDBCErrors> might be a good read. |
- If you experience troubles, <https://www.ntu.edu.sg/home/ehchua/programming/howto/ErrorMessages.html#JDBCErrors> might be a good read. |
5305 |
|
- [@Textbook6, 13.3.2] is a condensed, but good read. Many textbook on Java includes a part on Databases, cf. for instance the [Gaddis2014, Chapter 16]. |
|
|
5266 |
|
- [@Textbook6, 13.3.2] is a condensed, but good read. Many textbook on Java includes a part on Databases, cf. for instance [Gaddis2014, Chapter 16]. |
5306 |
5267 |
|
|
5307 |
5268 |
|
|
5308 |
|
Problem +.# |
|
5309 |
|
~ \ |
|
5310 |
|
|
|
5311 |
|
In the archive, navigate to `code/sql/`, open and read `HW\_ebookshop.sql`. |
|
5312 |
|
|
|
5313 |
|
Then, open a terminal (or command-line interpreter), navigate to the folder where you stored that file (using `cd`), and type |
|
5314 |
|
|
|
5315 |
|
~~~{.bash} |
|
5316 |
|
mysql -u testuser -p < HW_ebookshop.sql |
|
5317 |
|
~~~ |
|
5318 |
|
|
|
5319 |
|
for linux, or (something like) |
|
5320 |
|
|
|
5321 |
|
~~~{.bash} |
|
5322 |
|
"C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql.exe" -u testuser -p < HW_ebookshop.sql |
|
5323 |
|
~~~ |
|
5324 |
|
|
|
5325 |
|
for Windows. |
|
5326 |
|
|
|
5327 |
|
You just discovered MySQL's batch mode, that perform *series* of instructions from a file. |
|
5328 |
|
You can easily make sure that the database and the table were indeed created, and the values inserted. |
|
5329 |
|
|
|
5330 |
|
--- |
|
5331 |
|
|
|
5332 |
|
Problem +.# |
|
5333 |
|
~ \ |
|
|
5269 |
|
Problem (MySQL's batch mode and HW_EBOOKSHOP.sql) +.#mysql_batch |
|
5270 |
|
~ |
5334 |
5271 |
|
|
5335 |
|
This exercise supposes you successfully completed Problem~ \ref{qu:batch}. |
|
5336 |
|
We will compile and execute your first database application, using Java and MySQL. |
|
5337 |
|
|
|
5338 |
|
- I will assume that you have MySQL installed and set-up as indicated in Homeworks \#1 and \#2. |
|
5339 |
|
- I will assume that you have Java installed. If not, please refer to <http://spots.augusta.edu/caubert/teaching/general/java/> for a simple program and the instructions to compile and execute it. |
|
5340 |
|
- We need to set up the *driver* (or *connector*) to make the java `sql` API and MySQL communicate. To do so, |
|
5341 |
|
\begin{- ize} |
|
5342 |
|
- Go to <https://dev.mysql.com/downloads/connector/j/> |
|
5343 |
|
- Click on "Download" in front of "Platform Independent (Architecture Independent), ZIP Archive" |
|
5344 |
|
- Look for the (somewhat hidden) "No thanks, just start my download." |
|
5345 |
|
- You will download a file named "mysql-connector-java-***.zip", where `***` is the version number. |
|
5346 |
|
- Upon completion of the download, unzip the file, and locate the "mysql-connector-java-***-bin.jar" file. |
|
5347 |
|
- Copy that file in `code/java/`. |
|
5348 |
|
\end{- ize} |
|
5349 |
|
- Open a terminal in that same folder, and compile `FirstProg.java`, using |
|
|
5272 |
|
In the archive, navigate to `code/sql/` and open `HW_EBOOKSHOP.sql`. |
|
5273 |
|
Then, open a terminal (or command-line interpreter), navigate to the folder where you stored that file (using `cd`), and type |
5350 |
5274 |
|
|
5351 |
5275 |
~~~{.bash} |
~~~{.bash} |
5352 |
|
javac FirstProg.java |
|
|
5276 |
|
mysql -u testuser -p < HW_EBOOKSHOP.sql |
5353 |
5277 |
~~~ |
~~~ |
5354 |
5278 |
|
|
5355 |
|
(or an equivalent command for windows). |
|
5356 |
|
Normally, nothing will be printed, but a `FirstProg.class` file will be created. |
|
5357 |
|
- Now, execute that program, using |
|
|
5279 |
|
for linux, or (something like) |
5358 |
5280 |
|
|
5359 |
5281 |
~~~{.bash} |
~~~{.bash} |
5360 |
|
java -cp .:mysql-connector-java-***-bin.jar FirstProg |
|
|
5282 |
|
"C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql.exe" -u testuser -p < HW_EBOOKSHOP.sql |
5361 |
5283 |
~~~ |
~~~ |
5362 |
5284 |
|
|
5363 |
|
in Linux, or |
|
5364 |
|
|
|
5365 |
|
~~~{.bash} |
|
5366 |
|
java -cp .;mysql-connector-java-***-bin.jar FirstProg |
|
5367 |
|
~~~ |
|
|
5285 |
|
for Windows. |
5368 |
5286 |
|
|
5369 |
|
in Windows. |
|
5370 |
|
The `-cp` option lists the places where java should look for the class used in the program: we are explicitely asking java to use the `mysql-connector-java-***-bin.jar` executable to execute our `FirstProg` executable. |
|
5371 |
|
Try to execute `FirstProg` without that flag, and see what happens. |
|
|
5287 |
|
You just discovered MySQL's batch mode, that perform *series* of instructions from a file. |
|
5288 |
|
You can easily make sure that the database and the table were indeed created, and the values inserted. |
5372 |
5289 |
|
|
5373 |
|
|
|
5374 |
|
Solution +.# |
|
5375 |
|
|
|
5376 |
|
~~~{.bash} |
|
5377 |
|
$ java FirstProg |
|
5378 |
|
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/HW_ebookshop |
|
5379 |
|
at java.sql.DriverManager.getConnection(DriverManager.java:689) |
|
5380 |
|
at java.sql.DriverManager.getConnection(DriverManager.java:247) |
|
5381 |
|
at FirstProg.main(FirstProg.java:9) |
|
5382 |
|
~~~ |
|
|
5290 |
|
--- |
5383 |
5291 |
|
|
5384 |
5292 |
Problem +.# |
Problem +.# |
5385 |
|
~ \ Read, execute, break, edit, compile, patch, hack and (most importantly) understand the following program: |
|
5386 |
|
|
|
5387 |
|
~~~{.java .numberlines} |
|
5388 |
|
/* |
|
5389 |
|
|
|
5390 |
|
This is a long program, introducing: |
|
5391 |
|
I. How to pass options when connecting to the database, |
|
5392 |
|
II. How to create a table |
|
5393 |
|
III. How to insert values |
|
5394 |
|
IV. How to use prepared statements |
|
5395 |
|
V. How to read backward and write in ResultSets |
|
5396 |
|
|
|
5397 |
|
If you want to run this program multiple times, you have to either: |
|
5398 |
|
|
|
5399 |
|
1. Comment first statement of II. Creating a table |
|
5400 |
|
2. Change the name of the schema, from HW_DBPROG to whatever you want |
|
5401 |
|
3. Drop the Dvd table: connect to your database, and then enter |
|
5402 |
|
USE HW_DBPROG; |
|
5403 |
|
DROP TABLE Dvd; |
|
5404 |
|
Or do it from within your program! |
|
5405 |
|
|
|
5406 |
|
If you use option 1, you will keep inserting tuples in your table: cleaning it with |
|
5407 |
|
DELETE FROM Dvd; |
|
5408 |
|
can help. You can do it from within the program! |
|
5409 |
|
*/ |
|
5410 |
|
|
|
5411 |
|
import java.sql.*; |
|
|
5293 |
|
~ |
5412 |
5294 |
|
|
5413 |
|
public class AdvancedProg { |
|
5414 |
|
public static void main(String[] args) { |
|
5415 |
|
try ( |
|
5416 |
|
|
|
5417 |
|
/* |
|
5418 |
|
* I. Passing options to the dababse |
|
5419 |
|
*/ |
|
5420 |
|
|
|
5421 |
|
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/HW_DBPROG" |
|
5422 |
|
+ "?user=testuser" |
|
5423 |
|
+ "&password=password" |
|
5424 |
|
+ "&allowMultiQueries=true" |
|
5425 |
|
+ "&createDatabaseIfNotExist=true" |
|
5426 |
|
+ "&useSSL=true"); |
|
5427 |
|
|
|
5428 |
|
// Read about other options at |
|
5429 |
|
// https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html |
|
5430 |
|
// https://jdbc.postgresql.org/documentation/head/connect.html |
|
5431 |
|
|
|
5432 |
|
Statement stmt = conn.createStatement(); |
|
5433 |
|
) { |
|
5434 |
|
|
|
5435 |
|
/* |
|
5436 |
|
* II. Creating a table |
|
5437 |
|
*/ |
|
5438 |
|
|
|
5439 |
|
stmt.execute("CREATE TABLE Dvd (" + |
|
5440 |
|
"Title CHAR(25) PRIMARY KEY, " + |
|
5441 |
|
"Minutes INTEGER, " + |
|
5442 |
|
"Price DOUBLE)"); |
|
5443 |
|
|
|
5444 |
|
/* If we were to execute |
|
5445 |
|
* SHOW TABLES |
|
5446 |
|
* directly in the MySQL interpreter, this would display at the screen |
|
5447 |
|
* |
|
5448 |
|
* +--------------------------+ |
|
5449 |
|
* | Tables_in_HW_NewDataBase | |
|
5450 |
|
* +--------------------------+ |
|
5451 |
|
* | Dvd | |
|
5452 |
|
* +--------------------------+ |
|
5453 |
|
* |
|
5454 |
|
* But here, to access this information, we will use the connection's metadata. |
|
5455 |
|
*/ |
|
5456 |
|
|
|
5457 |
|
DatabaseMetaData md = conn.getMetaData(); |
|
5458 |
|
// DatabaseMetaData is a class used to get information about the database: the driver, the user, the versions, etc. |
|
5459 |
|
|
|
5460 |
|
ResultSet rs = md.getTables(null, null, "%", null); |
|
5461 |
|
|
|
5462 |
|
/* |
|
5463 |
|
* You can read at |
|
5464 |
|
* https://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getTables(java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String[]) |
|
5465 |
|
* the full specification of this method. |
|
5466 |
|
* All you need to know, for now, is that the third parameter is |
|
5467 |
|
* String tableNamePattern, |
|
5468 |
|
* i.e., what must match the table name as it is stored in the database |
|
5469 |
|
* Here, by using the wildcard "%", we select all the table names. |
|
5470 |
|
* We can then iterate over the ResultSet as usual: |
|
5471 |
|
*/ |
|
5472 |
|
|
|
5473 |
|
while (rs.next()) { |
|
5474 |
|
System.out.println(rs.getString(3)); // In the ResultSet returned by getTables, 3 is the TABLE_NAME. |
|
5475 |
|
} |
|
|
5295 |
|
This exercise supposes you successfully completed @problem:mysql_batch. |
|
5296 |
|
We will compile and execute your first database application, using Java and MySQL. |
|
5297 |
|
|
|
5298 |
|
- I will assume that you have MySQL installed and set-up as indicated in Homeworks \#1 and \#2. |
|
5299 |
|
- I will assume that you have Java installed. If not, please refer to <http://spots.augusta.edu/caubert/teaching/general/java/> for a simple program and the instructions to compile and execute it. |
|
5300 |
|
- We need to set up the *driver* (or *connector*) to make the java `sql` API and MySQL communicate. To do so, |
|
5301 |
|
- Go to <https://dev.mysql.com/downloads/connector/j/> |
|
5302 |
|
- Click on "Download" in front of "Platform Independent (Architecture Independent), ZIP Archive" |
|
5303 |
|
- Look for the (somewhat hidden) "No thanks, just start my download." |
|
5304 |
|
- You will download a file named "mysql-connector-java-***.zip", where `***` is the version number. |
|
5305 |
|
- Upon completion of the download, unzip the file, and locate the "mysql-connector-java-***-bin.jar" file. |
|
5306 |
|
- Copy that file in `code/java/`. |
|
5307 |
|
- Open a terminal in that same folder, and compile `FirstProg.java`, using `javac FirstProg.java`{.bash} (or an equivalent command for windows). |
|
5308 |
|
Normally, nothing will be printed, but a `FirstProg.class` file will be created. |
|
5309 |
|
- Now, execute that program, using |
|
5310 |
|
~~~{.bash} |
|
5311 |
|
java -cp .:mysql-connector-java-***-bin.jar FirstProg |
|
5312 |
|
~~~ |
5476 |
5313 |
|
|
5477 |
|
/* |
|
5478 |
|
* III. Inserting values |
|
5479 |
|
*/ |
|
5480 |
|
|
|
5481 |
|
String sqlStatement = "INSERT INTO Dvd VALUES ('Gone With The Wind', 221, 3);"; |
|
5482 |
|
int rowsAffected = stmt.executeUpdate(sqlStatement); |
|
5483 |
|
System.out.print(sqlStatement + " changed " + rowsAffected + " row(s).\n"); |
|
|
5314 |
|
in Linux, or |
5484 |
5315 |
|
|
5485 |
|
|
|
5486 |
|
/* |
|
5487 |
|
* Batch Insertion |
|
5488 |
|
*/ |
|
5489 |
|
|
|
5490 |
|
String insert1 = "INSERT INTO Dvd VALUES ('Aa', 129, 0.2)"; |
|
5491 |
|
String insert2 = "INSERT INTO Dvd VALUES ('Bb', 129, 0.2)"; |
|
5492 |
|
String insert3 = "INSERT INTO Dvd VALUES ('Cc', 129, 0.2)"; |
|
5493 |
|
String insert4 = "INSERT INTO Dvd VALUES ('DD', 129, 0.2)"; |
|
5494 |
|
|
|
5495 |
|
// Method 1: Using executeUpdate, if the option allowMultiQueries=true was passed in the url given to getConnection and your DBMS supports it. |
|
5496 |
|
stmt.executeUpdate(insert1 + ";" + insert2); |
|
5497 |
|
|
|
5498 |
|
// Method 2: Using the addBatch and executeBatch methods |
|
5499 |
|
stmt.addBatch(insert3); |
|
5500 |
|
stmt.addBatch(insert4); |
|
5501 |
|
stmt.executeBatch(); |
|
5502 |
|
|
|
5503 |
|
|
|
5504 |
|
/* |
|
5505 |
|
* IV. Prepared Statements |
|
5506 |
|
*/ |
|
5507 |
|
|
|
5508 |
|
// Example 1 |
|
5509 |
|
sqlStatement = "SELECT title FROM Dvd WHERE Price <= ?"; // We have a string with an empty slot, represented by "?". |
|
5510 |
|
PreparedStatement ps = conn.prepareStatement(sqlStatement); // We create a PreparedStatement object, using that string with an empty slot. |
|
5511 |
|
float maxprice = 0.5f; |
|
5512 |
|
ps.setFloat(1, maxprice); // This statement says "Fill the first slot with the value of maxprice". |
|
5513 |
|
ResultSet result = ps.executeQuery(); // And then we can execute the query, and display the results: |
|
5514 |
|
|
|
5515 |
|
System.out.printf("For %.2f you can get:\n", maxprice); |
|
5516 |
|
|
|
5517 |
|
while(result.next()){ |
|
5518 |
|
System.out.printf("\t %s \n", result.getString(1)); |
|
5519 |
|
} |
|
5520 |
|
|
|
5521 |
|
// Example 2 |
|
5522 |
|
sqlStatement = "INSERT INTO Dvd VALUES (?, ?, ?)"; // Now, our string has 3 empty slots, and it is an INSERT statement. |
|
5523 |
|
PreparedStatement preparedStatement = conn.prepareStatement(sqlStatement); |
|
|
5316 |
|
~~~{.bash} |
|
5317 |
|
java -cp .;mysql-connector-java-***-bin.jar FirstProg |
|
5318 |
|
~~~ |
5524 |
5319 |
|
|
5525 |
|
preparedStatement.setString(1, "The Great Dictator"); |
|
5526 |
|
preparedStatement.setInt(2, 124); |
|
5527 |
|
preparedStatement.setFloat(3, 5.4f); |
|
|
5320 |
|
in Windows. |
|
5321 |
|
The `-cp` option lists the places where java should look for the class used in the program: we are explicitely asking java to use the `mysql-connector-java-***-bin.jar` executable to execute our `FirstProg` executable. |
|
5322 |
|
Try to execute `FirstProg` without that flag, and see what happens. |
5528 |
5323 |
|
|
5529 |
|
rowsAffected = preparedStatement.executeUpdate(); // You can check "by hand" that this statement was correctly executed. |
|
5530 |
|
System.out.print(preparedStatement.toString() + " changed "+ rowsAffected + " row(s).\n"); |
|
|
5324 |
|
Solution +.# |
|
5325 |
|
~ |
5531 |
5326 |
|
|
5532 |
|
|
|
5533 |
|
// If we try to mess things up, i.e., provide wrong datatypes: |
|
5534 |
|
preparedStatement.setString(1, "The Great Dictator"); |
|
5535 |
|
preparedStatement.setString(2, "The Great Dictator"); |
|
5536 |
|
preparedStatement.setString(3, "The Great Dictator"); |
|
5537 |
|
|
|
5538 |
|
// Java compiler will be ok, but we'll have an error at execution time when executing the query. You can uncomment the line below to see for yourself. |
|
5539 |
|
//rowsAffected = preparedStatement.executeUpdate(); |
|
5540 |
|
|
|
5541 |
|
// Of course, we can use prepared statement inside loops. |
|
5542 |
|
for (int i = 1; i < 5; i++) { |
|
5543 |
|
preparedStatement.setString(1, "Saw " + i); |
|
5544 |
|
preparedStatement.setInt(2, 100); |
|
5545 |
|
preparedStatement.setFloat(3, .5f); |
|
5546 |
|
preparedStatement.executeUpdate(); |
|
5547 |
|
} |
|
5548 |
|
|
|
5549 |
|
/* |
|
5550 |
|
* V. Reading backward and writing in ResultSets |
|
5551 |
|
*/ |
|
5552 |
|
|
|
5553 |
|
// To read backward and write in ResultSets, you need to have a statement with certain options: |
|
5554 |
|
|
|
5555 |
|
Statement stmtNew = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); |
|
5556 |
|
|
|
5557 |
|
/* |
|
5558 |
|
* Those options change two things about the ResultSet we obtain using this statement |
|
5559 |
|
* |
|
5560 |
|
* The first argument is the scrolling level: |
|
5561 |
|
* TYPE_FORWARD_ONLY = default. |
|
5562 |
|
* TYPE_SCROLL_INSENSITIVE = can scroll, but updates don't impact result set. |
|
5563 |
|
* TYPE_SCROLL_SENSITIVE = can scroll, update impact result set. |
|
5564 |
|
* |
|
5565 |
|
* The second argument is the concurrency level: |
|
5566 |
|
* CONCUR_READ_ONLY: default. |
|
5567 |
|
* CONCUR_UPDATABLE: we can change the database without issuing SQL statement. |
|
5568 |
|
*/ |
|
5569 |
|
|
|
5570 |
|
/* |
|
5571 |
|
* Reading backward |
|
5572 |
|
*/ |
|
5573 |
|
|
|
5574 |
|
sqlStatement = "SELECT title FROM Dvd WHERE Price < 1;"; |
|
5575 |
|
result = stmtNew.executeQuery(sqlStatement); |
|
|
5327 |
|
~~~{.bash} |
|
5328 |
|
$ java FirstProg |
|
5329 |
|
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/HW_EBOOKSHOP |
|
5330 |
|
at java.sql.DriverManager.getConnection(DriverManager.java:689) |
|
5331 |
|
at java.sql.DriverManager.getConnection(DriverManager.java:247) |
|
5332 |
|
at FirstProg.main(FirstProg.java:9) |
|
5333 |
|
~~~ |
5576 |
5334 |
|
|
5577 |
|
System.out.println("For $1, you can get:"); |
|
5578 |
|
|
|
5579 |
|
if (result.last()) { // We can jump to the end of the ResultSet |
|
5580 |
|
System.out.print(result.getString("Title") + " "); |
|
5581 |
|
} |
|
5582 |
|
|
|
5583 |
|
System.out.print("and also, (in reverse order)"); |
|
5584 |
|
|
|
5585 |
|
while (result.previous()) { // Now we can scroll back! |
|
5586 |
|
System.out.print(result.getString("Title") + " "); |
|
5587 |
|
} |
|
5588 |
|
|
|
5589 |
|
/* |
|
5590 |
|
* Other methods to navigate in ResultSet: |
|
5591 |
|
* first() |
|
5592 |
|
* last() |
|
5593 |
|
* next() |
|
5594 |
|
* previous() |
|
5595 |
|
* relative(x) : move cursor x times (positive = forward, negative = backward) |
|
5596 |
|
* absolute(x): move to the row number x. 1 is the first. |
|
5597 |
|
*/ |
|
5598 |
|
|
|
5599 |
|
/* |
|
5600 |
|
* Changing the values |
|
5601 |
|
*/ |
|
5602 |
|
|
|
5603 |
|
System.out.print("\n\nLet us apply a 50% discount. Currently, the prices are:\n"); |
|
5604 |
|
|
|
5605 |
|
sqlStatement = "SELECT title, price FROM Dvd;"; |
|
5606 |
|
result = stmtNew.executeQuery(sqlStatement); |
|
5607 |
|
while (result.next()) { |
|
5608 |
|
System.out.printf("%20s \t $%3.2f\n", result.getString("title") , result.getDouble("price")); |
|
5609 |
|
} |
|
5610 |
|
|
|
5611 |
|
|
|
5612 |
|
result.absolute(0); // We need to scroll back! |
|
5613 |
|
|
|
5614 |
|
while (result.next()) { |
|
5615 |
|
double current = result.getDouble("price"); |
|
5616 |
|
result.updateDouble("price", (current * 0.5)); |
|
5617 |
|
result.updateRow(); |
|
5618 |
|
} |
|
5619 |
|
System.out.print("\n\nAfter update, the prices are:\n"); |
|
5620 |
|
|
|
5621 |
|
result.absolute(0); // We need to scroll back! |
|
5622 |
|
|
|
5623 |
|
while (result.next()) { |
|
5624 |
|
System.out.printf("%20s \t $%3.2f\n", result.getString("title") , result.getDouble("price")); |
|
5625 |
|
} |
|
5626 |
|
|
|
5627 |
|
|
|
5628 |
|
conn.close(); |
|
5629 |
|
} catch (SQLException ex) { |
|
5630 |
|
ex.printStackTrace(); |
|
5631 |
|
} |
|
5632 |
|
} |
|
5633 |
|
} |
|
5634 |
|
~~~ |
|
5635 |
|
|
|
|
5335 |
|
Problem +.# |
|
5336 |
|
~ |
5636 |
5337 |
|
|
|
5338 |
|
Read, execute, break, edit, compile, patch, hack and (most importantly) understand the following program: |
5637 |
5339 |
|
|
|
5340 |
|
```{.sqlmysql .numberLines include=code/java/AdvancedProg.java} |
|
5341 |
|
``` |
5638 |
5342 |
|
|
5639 |
5343 |
--- |
--- |
5640 |
5344 |
|
|
|
... |
... |
public class AdvancedProg { |
5648 |
5352 |
|
|
5649 |
5353 |
- Who is threatening you? |
- Who is threatening you? |
5650 |
5354 |
- What are the risks? |
- What are the risks? |
5651 |
|
|
|
5652 |
5355 |
#. Loss of integrity (improper modification) |
#. Loss of integrity (improper modification) |
5653 |
5356 |
#. Loss of availability |
#. Loss of availability |
5654 |
5357 |
#. Loss of confidentiality (unauthorized disclosure) |
#. Loss of confidentiality (unauthorized disclosure) |
5655 |
|
|
|
5656 |
5358 |
- "You are as strong as your weakest link." |
- "You are as strong as your weakest link." |
5657 |
5359 |
- Never trust the user or their computer. |
- Never trust the user or their computer. |
5658 |
5360 |
|
|
|
5361 |
|
|
5659 |
5362 |
### Control measures |
### Control measures |
5660 |
5363 |
|
|
5661 |
5364 |
- Access control (user account, passwords, restrictions) |
- Access control (user account, passwords, restrictions) |
|
... |
... |
Think of BSON as a binary representation of JSON (JavaScript Object Notation) do |
5880 |
5583 |
|
|
5881 |
5584 |
An example of XML (Extensible Markup Languag) document (you can actually convert from XML to JSON): |
An example of XML (Extensible Markup Languag) document (you can actually convert from XML to JSON): |
5882 |
5585 |
|
|
5883 |
|
~~~{.xml} |
|
|
5586 |
|
~~~{.xml .numberLines} |
5884 |
5587 |
<shiporder orderid="889923"> |
<shiporder orderid="889923"> |
5885 |
5588 |
<orderperson>John Smith</orderperson> |
<orderperson>John Smith</orderperson> |
5886 |
5589 |
<shipto> |
<shipto> |
|
... |
... |
Each MongoDB instance has multiple databases, each database can have multiple co |
5921 |
5624 |
|
|
5922 |
5625 |
Two documents (delimited by `[`…`]`, used to delimit an arry of document). |
Two documents (delimited by `[`…`]`, used to delimit an arry of document). |
5923 |
5626 |
|
|
5924 |
|
~~~{.json} |
|
|
5627 |
|
~~~{.json .numberLines} |
5925 |
5628 |
[ |
[ |
5926 |
5629 |
{ |
{ |
5927 |
5630 |
"firstname": "Martin", |
"firstname": "Martin", |
|
... |
... |
db.collection.find() |
6076 |
5779 |
|
|
6077 |
5780 |
We can construct lists of documents and insert them: |
We can construct lists of documents and insert them: |
6078 |
5781 |
|
|
6079 |
|
~~~{.java} |
|
|
5782 |
|
~~~{.java .numberLines} |
6080 |
5783 |
List<Document> documents = new ArrayList<Document>(); |
List<Document> documents = new ArrayList<Document>(); |
6081 |
5784 |
for (int i = 0; i < 10; i++) { |
for (int i = 0; i < 10; i++) { |
6082 |
5785 |
documents.add(new Document("i", i)); |
documents.add(new Document("i", i)); |