jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/dangdang jdbc.username=root jdbc.password=root
----------------------------------------------------------------
class.forName(oracle.jdbc.OracleDriver) jdbc:oracle:thin:@localhost:1521:xe "com.mysql.jdbc.Driver" jdbc:mysql://localhost:3306/student
JDBC 一,JDBC内容 接口:sun定义 java.sql 和javax.sql 实现类:数据库厂商提供 二,jdbc使用 1,如何使用jar --dos使用 classpath中添加jar路径 2,jdbc流程 a:注册驱动类 b:创建链接 c:创建statement(不常用) d:执行sql e:处理结果 f:释放资源statement 也要close get列时序号从1开始 3,prepareStatementjava.sql statement子接口 PrepareStatement ps =conn.prepareStatement(sql); ps.setxxx(1,name) ps.setxxx(2,password) ps.exq exu (使用午餐的构造) 里面的参数不用拼接 在执行前时插入 4.两者区别 state = com.cre... stat.execute(sql) 不安全,有注入 prep = conn.create..(sql) prep.execute() 无sql注入,切性能更高 服务器操作 1检查权限, 2检查语法 3,sql转化为内部指令 前三是编译过程 4,执行指令 statement创建成功时不发送sql,执行时发送 例:for(int i=0;i<10;i++{ stat.ex(insert...) } prep 可只把setxxx写在for循环中 只用编译一次即可,所以说也叫作预编译语句 stat:异构sql prep:同构sql(只有参数不同 日期转换:日期转换 strDate --- util.Date---sql.Date //插入或修改字段的类型是时间类型Date时,需要使用时间转换 // 1.设置格式,格式应与字符串相匹配。和数据库中to_date方法类似 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // 2.strDate--util.Date Date util Date = format.parse(strDate); // 3.util.Date---sql.Date java.sql.Date date = new java.sql.Date(utilDate.getTime());
1.事务控制 JDBC默认的是自动的事务提交 相关API:控制事务提交的对象为连接 Connection //设置事务提交方式为手动 conn.setAutoCommit(false);//true---自动提交 false---手动提交 //事务提交 conn.commit(); //事务回滚 conn.rollback();
2.业务类方法的书写步骤 //1.获取Connection conn = JdbcUtil2.getConnection(); System.out.println("这是service获得连接:"+conn); //2.设置事务提交为手动提交 conn.setAutoCommit(false); //3.调用DAO中的方法完成业务操作 dao.insert(clazz); //4.提交事务 or 回滚事务 conn.commit(); conn.rollback
3.当前的事务控制存在问题 首先service层获得的连接与Dao不是一条 其次通过单例可以解决这样的问题,但是会存在线程不安全的情况。 为了解决线程安全,且可以控制事务的问题 我们需要使用线程局部表变量,ThreadLocal ~~~
#### 九、线程局部变量
~~~java 线程局部变量,再多线程环境下,可以为每个使用该变量的线程 分配线程内部独有的 线程变量值。
1.API: ThreadLocal th = new ThreadLocal(); th.set(obj);//往线程局部变量中设置 obj = th.get();//返回该线程局变量的值 th.remove();//移除该线程局变量的值
2.作用: 1)保证 同一个线程内部 使用相同的值 2)保证不用线程使用不用的值
3.原理: 当调用 set方法时,会将当前线程对象当做Key,将set中的参数当做value 放入到一个map集合中 ,这个集合由Thread进行管理的。 当使用get方法时,以当前线程为key来向该map集合取值。
4.使用ThreadLoacl来修改getConnection方法
//创建连接的方法
private static ThreadLocal<Connection> th = new ThreadLocal<Connection>();
public static Connection getConnection(){
Connection conn = th.get();
if(conn==null){//如果为空就创建
//1.注册驱动
try {
Class.forName(p.getProperty("driver"));
//2.建立连接
conn = DriverManager.getConnection(p.getProperty("url"),p.getProperty("username"),p.getProperty("password"));
//3.并把连接放入ThreadLocal
th.set(conn);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return conn;
}
if(conn!=null){
try {
conn.close();
th.remove();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
注意:1)在控制事务时,dao内不要关闭连接
2)在关闭连接后,要清空线程局部变量中的废连接
~~~
#### 十、JDBC的
分层分包:
都在域名倒写的包下 比如 com.zzu.xjh
1)sql 存放了关于该项目相关的一些sql语句文档
2)conf 放置了配置文件
3)util 放置了该项目的工具类
4)test 放置了该项目相关的测试类
5)entity 放置了该项目的实体类
6)dao 放置该项目的DAO接口 在该包下应有一个impl包 里面放置 对应dao的实现类
7)service 放置该项目的service 接口 在该包下应有一个impl包 里面放置 对应service 的实现类
8)conroller/action 放置该项目的控制器
9)view (可能出现)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class JdbcTemplate<T> {
/*
* 专门完成增 删 改操作
*
* insert into t_user (id,name,password) values (suns_seq.nextval,?,?);
*
* jdbcTemplate.update(sql,new Object[]{"suns","123456"});
*
* delete from t_user where id = ?
*
* jdbcTemplate.delete(sql,new Object[]{1});
*
* update t_product set name=?,price=? where id = ?
*
* jdbcTemplate.update(sql,new Object[]{"suns",10.2,1});
*
* 可变长参数 1 等同于数组
* 2 只能放在参数表最后 ,只能有一个
*
* "delete from t_user where id = 10";
*
*/
public void update(String sql,Object... args){
Connection conn = null;
PreparedStatement pstmt = null;
try{
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
if(hasUpdateParam(args)){
for(int i=0;i<args.length;i++){
pstmt.setObject(i+1,args[i]);
}
}
pstmt.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.close(null, pstmt);
}
}
private boolean hasUpdateParam(Object... args) {
return args.length!=0;
}
public List<T> query(String sql,RowMapper<T> rowMapper,Object... args){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<T> rets = new ArrayList<T>();
try{
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
if(hasUpdateParam(args)){
for(int i=0;i<args.length;i++){
pstmt.setObject(i+1, args[i]);
}
}
rs = pstmt.executeQuery();
while(rs.next()){
T ret = rowMapper.mapRow(rs);
rets.add(ret);
}
return rets;
}catch(Exception e){
e.printStackTrace();
return null;
}finally{
JDBCUtil.close(null, pstmt, rs);
}
}
public T queryForObject(String sql,RowMapper<T> rowMapper,Object... args){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
T ret = null;
try{
conn = JDBCUtil.getConnection();
pstmt = conn.prepareStatement(sql);
if(hasUpdateParam(args)){
for(int i=0;i<args.length;i++){
pstmt.setObject(i+1, args[i]);
}
}
rs = pstmt.executeQuery();
if(rs.next()){
ret = rowMapper.mapRow(rs);
}
return ret;
}catch(Exception e){
e.printStackTrace();
return null;
}finally{
JDBCUtil.close(null, pstmt, rs);
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
/*
* 性能 效率 内存使用
* 维护性 (便于修改)
* 基本功能
*/
public class JDBCUtil {
private static Properties p = new Properties();
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
static{
//1 读入Properties文件
InputStream is = JDBCUtil.class.getResourceAsStream("/jdbc.properties");
//2 传入Properties集合
try {
p.load(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//创建连接
public static Connection getConnection() throws Exception{
Connection conn = tl.get();
if(conn==null){
Class.forName(p.getProperty("driver"));
conn = DriverManager.getConnection(p.getProperty("url"),p.getProperty("username"),p.getProperty("password"));
tl.set(conn);
return conn;
}
return conn;
}
//关闭资源
public static void close(Connection conn,PreparedStatement pstmt,ResultSet rs){
if(rs!=null){try{rs.close();}catch(Exception e){}}
if(pstmt!=null){try{pstmt.close();}catch(Exception e){}}
if(conn!=null){try{conn.close();tl.remove();}catch(Exception e){}}
}
public static void close(Connection conn,PreparedStatement pstmt){
if(pstmt!=null){try{pstmt.close();}catch(Exception e){}}
if(conn!=null){try{conn.close();tl.remove();}catch(Exception e){}}
}
}
1:1,一般是双向关系 建实体类时,两边都建 但建表时只有一个外键,建在不主要一方 定义表时,定义外键,做唯一 private Integer id; private String name; private String password; private Date birthday; private PassPort passport; --------------------------- private Integer id; private String serial; private Integer expire; private Person person; ---------------------------- create table t_person( id integer primary key, name varchar(12), password varchar(12), birthday date ); create table t_passport( id integer primary key, serial varchar(12), expire varchar(12), person_id integer unique references t_person(id) ); -------------------------------------------------------------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" > <mapper namespace="com.dzf.dao.o2o.PersonDao">
<resultMap id="personResultMap" type="Person" > <id property="id" column="person_id"/> <result property="name" column="person_name"/> <result property="password" column="person_password"/> <result property="birthday" column="person_birthday"/> <!-- 当只有passport一个对象 --> <association property="passport" javaType="PassPort"> <id property="id" column="passport_id"></id> <result property="serial" column="passport_serial"/> <result property="expire" column="passport_expire"/> </association> </resultMap> <select id="queryPersonById" resultMap="personResultMap"> select p.id as person_id,p.name as person_name,p.password as person_password,p.birthday as person_birthday ,pp.id as passport_id,pp.serial as passport_serial,pp.expire as passport_expire from t_person p inner join t_passport pp on p.id = pp.person_id where p.id = #{id} </select> </mapper>
---------------------------------------------- n:1 多对一单向 private Integer id; private String name; private Double salary; private Dept dept; private Integer id; private String code; private String name; create table t_employee( id integer primary key, name varchar(12), salary decimal(12,2), dept_id integer references t_dept(id) ); create table t_dept( id integer primary key, code varchar(12), name varchar(12) ); <resultMap id="employeeResultMap" type="Employee" > <id property="id" column="employee_id"/> <result property="name" column="employee_name"/> <result property="salary" column="employee_salary"/> <association property="dept" javaType="Dept"> <id property="id" column="dept_id"></id> <result property="code" column="dept_code"/> <result property="name" column="dept_name"/> </association> </resultMap> <select id="queryEmployeeByName" resultMap="employeeResultMap"> select e.id as employee_id,e.name as employee_name,e.salary as employee_salary, d.id as dept_id,d.code as dept_code,d.name as dept_name from t_employee e inner join t_dept d on e.dept_id = d.id where e.name = #{name} </select> <select id="queryDeptById" resultType="Dept"> select id,name,code from t_dept where id = #{id} </select> -------------------------------------------------------------------------------------------------------------- 1:n单向(n:1注意更换时 表不用改,表天生是双向的,俩表就一外键,在多的一方) private Integer id; private String name; private Double salary; private Integer id; private String code; private String name; private List<Employee> list = new ArrayList<Employee>();记得初始化 <resultMap id ="deptResultMap" type="Dept" > <id property="id" column = "dept_id"/> <result property = "code" column="dept_code"/> <result property = "name" column="dept_name"/> <collection property="list" ofType="Employee"><!-- 集合中元素类型 --> <id property="id" column="employee_id"/> <result property="name" column="employee_name"/> <result property="salary" column="employee_salary"/> </collection> </resultMap> <select id="queryDeptByName" resultMap="deptResultMap"> select d.id as dept_id ,d.code as dept_code,d.name as dept_name, e.id as employee_id,e.name as employee_name,e.salary as employee_salary from t_dept d inner join t_employee e on d.id = e.dept_id where d.name = #{name} </select> <select id="queryEmployeeById" resultType="Employee"> select id,name,salary from t_employee where id= #{id} </select> ----------------------------------------------------------------------------------------------------------------- 多对多双向,student,course 外键如何建?,不能建, 解决办法:引入第三张关系表
______________________________________________________________________
import java.sql.Connection;
import java.sql.SQLException;
/*
* 事务管理器 用于控制事务
*/
public class TransactionManager {
public static void begin(){
try {
Connection conn = JDBCUtil.getConnection();
conn.setAutoCommit(false);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void commit(){
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
conn.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtil.close(conn, null);
}
}
public static void rollback(){
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
conn.rollback();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtil.close(conn, null);
}
}
}