学习jdbc时记录的笔记

JDBC
java database connectvity 数据库连接
JDBC的本质:
JDBC是sun公司指定的一套接口。
接口都有调用者和实现者。
面对接口调用,面对接口实现类,这都属于面对接口编程。
java.sql.*; (这个软件包下有很多接口。)
为什么要面向接口编程
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面对抽象编程。
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。

为什么要面向接口编程?
	解耦合:降低程序的耦合度,提高程序的扩展力。
	多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
		建议:
			Animal a = new Cat();
			Animal a = new Dog();
			// 喂养的方法
			public void feed(Animal a){ // 面向父类型编程。
			
			}
		不建议:
			Dog d = new Dog();
			Cat c = new Cat();
			思考:为什么SUN制定一套JDBC接口呢?
	因为每一个数据库的底层实现原理都不一样。
	Oracle数据库有自己的原理。
	MySQL数据库也有自己的原理。
	MS SqlServer数据库也有自己的原理。
	....
	每一个数据库产品都有自己独特的实现原理。

JDBC的本质到底是什么?
	一套接口。
	mysql-connector-java-5.1.23-bin.jar(专业的名词驱动,其实就是以jar包的形式存在,里面有很多.class文件
	mysql驱动,oracle驱动,sqlserver驱动就是数据厂家通过jdbc接口编写的实现类,实现类被称为驱动
	我们通过jdbc接口可以调用这些类库,编写者是厂家,我们是调用者)
	实现原理:
	JDBC jdbc=new mysql();
	JDBC jdbc=new oracle();
	jdbc.getConnection();
	使用多态机制,父类引用指向子类对象,编译器会查看jdbc中是否有getConnection方法,有则编译器通过,
	实际运行的时候调用的是子类中的方法。
	通过反射机制创建对象
	Class c=Class.forName("mysql");
	JDBC jdbc=(JDBC)c.newInStance();//创建一个mysql对象,类型是JDBC
	IO + Properties,怎么快速绑定属性资源文件?

	//要求:第一这个文件必须在类路径下
	//第二这个文件必须是以.properties结尾。
	ResourceBundle bundle = ResourceBundle.getBundle("jdbc");//jdbc.properties
	String value = bundle.getString(classname);
	配置文件
	classname=mysql

JDBC开发前的准备工作,先从官网下载对应的驱动jar包,然后将其配置到环境变量classpath当中。

classpath=.;D:\course\06-JDBC\resources\MySql Connector Java 5.1.23\mysql-connector-java-5.1.23-bin.jar

以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量。
IDEA有自己的配置方式。

JDBC编程六步:
第一步:注册驱动(作用:告诉JAVA程序,即将要连接的是哪个品牌的数据库)
Class.forName(com.jdbc.cj.Driver)
在Driver这个类中有静态代码块
DriverManager.registerDriver(driver);
,要想静态代码块执行,通过反射机制可以实现,实际上通过反射其实就是调用了Driver类中的静态代码块的执行。
这种方式常用因为参数是一个字符串,字符串可以写在xxx.properties文件里面。

com.mysql.cj.jdbc.Driver是Driver驱动所在的位置
D:\MySQL数据库\jdbc学习\相关学习资源\MySql Connector Java 5.1.23\mysql驱动\com\mysql\jdbc\Driver.class
通过反射的机制获取Driver.classL文件
不使用反射:
java.sql
Class DriverManager
static void registerDriver(Driver driver)
注册了 DriverManager司机。
static void registerDriver(Driver driver, DriverAction da)
注册了 DriverManager司机。

Driver driver=new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);

Driver driver=new com.mysql.cj.jdbc.Driver();//高版本
第二步:获得连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭)
高版本需要加上?SSL=false&serverTimezone=UTC
String url=“jdbc:mysql://127.0.0.1:3306/数据库名”;
String username=“root”;
String password=“123456”;
Connection conn=DriverManager.getConnection(url,username,password)
等同于:
Connection conn=new com.mysql.jdbc.jdbc4Connection@41cf53f9//多态机制
java.sql.Connection类型指向mysql对象,当然数据库有多种,这种方式写死了,只需要调用getConnection方法就行

getConnection源码:
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();

    if (user != null) {
        info.put("user", user);
    }
    if (password != null) {
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));
}
 java规范中有要求:属性配置文件建议以.properties结尾,但这不是必须的。
这种以.properties结尾的文件在java中被称为:属性配置文件。
一般采用资源绑定
	//第二这个文件必须是以.properties结尾。
	ResourceBundle bundle = ResourceBundle.getBundle("jdbc");//jdbc.properties
	String value = bundle.getString(classname);

其中Properties是专门存放属性配置文件内容的一个类。

class Properties extends Hashtable<Object,Object> {
底层是一个hashtable

可以看成底层调用了rul,username,password,并把username和password翻入一个Properties类中,该类是一个文件配置类。
用来存放配置文件.最后通过反射获取当前注册的驱动,这就是为什么调用一个方法可以实现不同数据库连接。

数据库连接对象
第三步:获取数据库操作对象(专门执行sql语句的对象)Connection下的方法
Statement createStatement()
创建用于向数据库发送SQL语句的一 Statement对象。

Statement st=conn.createStatement() ;
第四步:执行sql语句(dql dml。。。)
statement stmt=conn.createstatement();
String sql=“insert into dept vlues()”;
int count=stmt.executeIpdate();//count是影响的数据条数dml
Connection类中的方法:

ResultSet executeQuery(String sql)
执行给定的SQL语句,返回一个 ResultSet对象。
int executeUpdate(String sql)
执行给定的SQL语句,这可能是一个 INSERT, UPDATE,或 DELETE语句或SQL语句不返回值,例如SQL DDL语句。
int executeUpdate(String sql, int autoGeneratedKeys)
执行给定的SQL语句和信号与给定的标志是否自动生成的 Statement物体产生的钥匙应提供检索的司机。
int executeUpdate(String sql, int[] columnIndexes)
执行给定的SQL语句和信号驱动程序,自动生成给定阵列应提供检索显示键。
int executeUpdate(String sql, String[] columnNames)
执行给定的SQL语句和信号驱动程序,自动生成给定阵列应提供检索显示键。
Connection getConnection()
产生这一 Statement检索对象的 Connection对象。

//查询:ResultSet rs=stmt.executeQuery();dql

第五步:查询结果集(只有当第四步执行的select语句的时候才有这第五步查询结果集。)
while(rs.next()){
Sting empno=rs.getString(1);
Sting ename=rs.getString(2);
Sting sal=rs.getString(3);
empno+“”+ename
//上述代码不健壮
String getString(int columnIndex)
检索指定的列在这 ResultSet对象的当前行的值作为java编程语言中的一个 String。
String getString(String columnLabel)
检索指定的列在这 ResultSet对象的当前行的值作为java编程语言中的一个 String。
int getInt(int columnIndex)
检索指定的列在这 ResultSet对象的当前行的值在java编程语言的一个 int。
int getInt(String columnLabel)
检索指定的列在这 ResultSet对象的当前行的值在java编程语言的一个 int。
long getLong(int columnIndex)
检索指定的列在这 ResultSet对象的当前行的值作为java编程语言中的一个 long。
long getLong(String columnLabel)
检索指定的列在这 ResultSet对象的当前行的值作为java编程语言中的一个 long。
还可以使用其他方法,获取指定的类型取出。

Sting empno=rs.getString(“empno”);
Sting ename=rs.getString(“ename”);
Sting sal=rs.getString(“sal”);
}
//ResultSet中的方法
boolean next()
从当前位置移动光标向前一行。

//jdbc所有下标都是从1开始,不是从0开始。
//getstring()不管数据库中的数据类型是什么,都是以string的形式取出。

第六步:释放资源(使用完资源之后一定要关闭资源。)
从小到大关闭先关闭:
如果是查询先关闭结果集:rs.close();//void close()
此次发布的 ResultSet对象的数据库和JDBC资源,而不是等待这种情况发生时,它立刻自动关闭。

数据库操作对象:stmt.close();
再关闭数据库连接对象:conn.close();
因为在try{}catch(){}finally{}中无法获取这两个对象。需要先创建两个值为null的对象在全局变量
Connection conn=null;
Statement stmt=null;

父类型指向子类型对象

url:统一资源定位符(网络中某个资源的绝对路径)
https://www.baidu.com/
http://182.61.200.7:80/index.html
url包括哪几个部分?
协议
ip
port
资源名
协议:
通信协议是通信之前就提前定好的。http:// 通信协议是通信之前提前订好的数据传送格式。
数据包具体怎么传数据,格式提前订好的。
182.61.200.7服务器ip地址
80服务器上软件的端口
index.html服务器上某个资源名

二:注册驱动的另一种方式:
如何让一块静态代码块执行,加载类-反射机制,class.forName("com.mysql.jdbc.Driver);
常用:因为参数是一个字符串,字符串可以写到XXX.properties文件中。
、使用资源绑定器绑定属性配置文件。
ResourceBundle bundle=ResourceBundle.getBundle(“jdbc”);
String driver=bundle.getstring(“driver”);

实际开发中不见把连接数据库的信息写死到java程序中。

数据查询 rsstmt.executequery(sql).
getstring()方法的特点是:不管数据库中的数据类型是什么,都以string的形式取出。

next();遍历结果集。

public class JDBCtesto1 {
public static void main(String[] args) {
//提变量
Connection connection=null;
Statement statement=null;
ResultSet resultSet =null;
try {
//创建mysql驱动
Class.forName(“com.mysql.cj.jdbc.Driver”);
//获取数据库连接对象
String url=“jdbc:mysql://localhost:3306/bjpowernode?SSL=false&serverTimezone=UTC”;
String username=“root”;
String password=“123456”;

      connection = DriverManager.getConnection(url, username, password);
            System.out.println("获取连接对象成功"+connection);
            //创建数据库操作对象
   statement = connection.createStatement();
        //执行sql

// String sql=“insert into dept values(180,‘aaa’,‘bbb’)”;
// int i = statement.executeUpdate(sql);
// System.out.println(“影响的数据表条数”+i);
//执行查询sql
String qsql="select deptno from dept ";
resultSet = statement.executeQuery(qsql);
//遍历结果集该操作只有sql是查询的时候才会有
while(resultSet.next()==true){
//下标的方式获取值,mysql数据库下标从1开始
// String resultSetString = resultSet.getString(1);
// System.out.println(resultSetString);
//名称的方式获取值,该名称是你的sql中的名称,如果修改了字段名必须使用修改后的字段名
String deptno = resultSet.getString(“deptno”);
System.out.println(deptno);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally {
//释放资源,无法获取在try中的变量需要往上提,称为全局变量,从小到大关闭
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

sql注入:
select * from user where username=xxx and password=xxx or 1=1
or 1=1
字符串拼接的时候,数据库通过
用户将非法信息,输入含有sql的关键字,并且关键字参与sql语句的编译过程
导致sql的原意被扭曲,进而达到sql注入。

解决sql注入:
即使用户把包含sql关键字传入也不会进行编译,采用 PreparedStatement代替statement, prepared(有准备的) PreparedStatement预编译的操作数据库对象
PreparedStatement代替statement,解决sql注入。
PreparedStatement是预编译,编译一次可执行m次,速度较快。采用预编译,编译的语句不变,后面就不用编译直接执行。
statement编译一次执行一次。因为sql一直在变,编译也是会变。
PreparedStatement在编译阶段做类型的安全检查,Statement则不会检查不会报错。


业务方面需要sql注入的时候用 Statement
需要用字符串拼接的时候用statement,比如京东商城的升序和降序,不能使用preparedstatemnt 比如select * from xxx group by desc
select * from xxx group by ? ps.setString(1,‘desc’);变成group by ‘desc’,preparedstatement的传值都是有类型的。
如果只是单纯传值使用preparedstatemnt

不是接口变量,而是一个接口类型的引用指向了一个实现给接口的对象,这是java中的一种多态现象
java中的接口不能被实例化,但是可以通过接口引用指向一个对象
这样通过接口来调用方法可以屏蔽掉具体的方法的实现,这是在JAVA编程中经常用到的接口回调,
也就是经常说的面向接口的编程

public class JDBCtesto2 {
public static void main(String[] args) {
//提变量
Connection connection=null;
PreparedStatement ps=null;//使用perparedStatement
ResultSet resultSet =null;
try {
//创建mysql驱动
Class.forName(“com.mysql.cj.jdbc.Driver”);
//获取数据库连接对象
String url=“jdbc:mysql://localhost:3306/bjpowernode?SSL=false&serverTimezone=UTC”;
String username=“root”;
String password=“123456”;

      connection = DriverManager.getConnection(url, username, password);
            System.out.println("获取连接对象成功"+connection);
            //创建数据库操作对象
	           String sql="insert into dept values(?,?,?)";//使用占位符的方式,这个sql在创建perparStatement对象之前创建,在创建perparStatement时被编译,Statement是创建之后编译sql会引起sql注入
		   //String sql=“"update dept set deptno=?danem=?,loc=? where deptno=?";
		   //delete from dept where deptno=?
   ps = connection.prepareStatement(sql);//这里处理sql
        //添加占位符数据sql
        ps.setInt(1,333);

ps.setString(2,“aaa”);
ps.setString(3,“ddd”);
ps.executeUpdate();
// System.out.println(“影响的数据表条数”+i);
//执行查询sql
// String qsql="select deptno from dept ";
// resultSet = statement.executeQuery(qsql);
// //遍历结果集该操作只有sql是查询的时候才会有
// while(resultSet.next()==true){
// //下标的方式获取值,mysql数据库下标从1开始
String resultSetString = resultSet.getString(1);
System.out.println(resultSetString);
// //名称的方式获取值,该名称是你的sql中的名称,如果修改了字段名必须使用修改后的字段名
// String deptno = resultSet.getString(“deptno”);
// System.out.println(deptno);
// }
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally {
//释放资源,无法获取在try中的变量需要往上提,称为全局变量,从小到大关闭
// try {
// resultSet.close();
// } catch (SQLException e) {
// e.printStackTrace();
// }
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
jdbc事务机制:
1.jdbc的事务是自动提交的,
只要执行任意一次DML语句,就自动提交一次,这是jdbc的事务行为,这是jdbc默认的事务
但是在实际开发过程中,通常都是N条DML语句联合才能完成的,必须保证这些dml语句在同一个事务中同时成功或同时失败。

测试结果:JDBC只奥执行任意一条DML语句,就提交给数据库一次。
alt+shift+insert批量编辑。

****工具类
jdbc工具类:将JVM实例写在static中只执行一次

悲观锁:在查询语句后加for update,查询的记录都将被锁住。事务必须排队执行,数据被锁住了,不允许并发。select * from dept for update
乐观锁:多线程:版本号被修改,发现被改,二线程就回滚。
事务1先修改,然后提交数据版本号从1.1变为1.2
事务2修改,提交的时候发现版本号是1.2回滚。
支持并发,事务也不需要排队,只需要一个版本号。
public class JDBCUtil {
/**
* 工具类的构造方法都是私有的,因为工具类中的方法都是静态,不需要new对象,直接采用类名调用
/
static{
/
*
* 静态代码块,在类加载的时候执行一次,并且只执行一次
/
try {
Class.forName(“com.mysql.cj.jdbc.Driver”);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/
*
* 静态方法
* 获取数据库连接对象
*/
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(“jdbc:mysql://localhost:3306/bjpowernode?serverTimeZone=UTC”,“root”,“123456”);
return connection;
}

/**
 * 关闭资源
 * @param con 数据库连接对象
 * @param ps 数据库操作对象
 * @param rs 结果集
 */
public static void close(Connection con, Statement ps, ResultSet rs){
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (ps != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if (con != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

}
public class JDBCtesto3 {
public static void main(String[] args) {
//提变量
Connection connection = null;
PreparedStatement ps = null;//使用perparedStatement
ResultSet resultSet = null;
try {
connection= JDBCUtil.getConnection();
String sql=“select * from dept where deptno=?”;
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,333);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()==true){
String deptno = resultSet.getString(“deptno”);
String dname = resultSet.getString(“dname”);
System.out.println(deptno+“名字”+dname);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(connection,ps,resultSet);
}
}
}

/*
jdbc事务机制:
1.jdbc的事务是自动提交的,
只要中心任意一次DML语句,就自动提交一次,这是jdbc的事务行为
但是在实际开发过程中,通常都是N条DML语句联合才能完成的,必须保证衙门这些dml语句在同一个事务中同时成功或同时失败。
重点三行代码:
conn.setAutoCommit(false);
conn.commit();
conn.rollback();
*/
public class logintest02 {
public static void main(String[] args) {
Connection con=null;
PreparedStatement ps=null;
ResultSet re=null;
try{
Class.forName(“com.mysql.cj.jdbc.Driver”);
//1.注册驱动

con=DriverManager.getConnection(“jdbc:mysql://localhost:3306/bjpowernode”,“root”,“123456”);
//2.建立连接通道
//将事务的自动提交改成手动提交
con.setAutoCommit(false);//开启事务
// String sql=“insert into dept(deptno,dname,loc) values(?,?,?)”;
// String sql=“update dept set dname=‘张三’ ,LOC=‘广济大道’ where deptno=900”;
String sql=“update dept set dname=? ,LOC=? where deptno=?”;
// String sql=“delete from dept where deptno=900”;
// String sql=“delete from dept where deptno=?”;
//3.获取数据库对象
ps=con.prepareStatement(sql);
//4.执行sql语句
// ps.setString(1,“900”);
// ps.setString(2,“大额贷款”);
// ps.setString(3,“上海”);
ps.setString(1,“语句1”);
ps.setString(2,“北京”);
ps.setString(3,“1”);
int count=ps.executeUpdate();
System.out.println(count);
//语句二
ps.setString(1,“语句2”);
ps.setString(2,“中国的”);
ps.setString(3,“60”);
//ps.setString(1,“80”);
//5.查询结果集
count=ps.executeUpdate();
System.out.println(count);
//程序能够走到这里说明程序没有异常,手动提交。
con.commit();
//re=ResultSet.next();
//6.关闭资源
}
catch (NullPointerException e){
e.printStackTrace();//打印堆栈的跟踪信息
e.toString();//打印异常的产生原因
e.getMessage();// 异常信息描述字符串
}
catch (Exception e){
if(con!=null){
try{
con.rollback();//事务回滚
}catch (SQLException e1){
e1.printStackTrace();
}

}
//没有抛出异常会报错
        e.printStackTrace();
    }

//catch ( ArithmeticException e){
// //没有抛出异常会报错
// e.printStackTrace();
//}
finally{
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(re!=null){
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

*随机查询mysql

  1. Oracle,随机查询查询语句-20条

select * from

(
select * from 表名
order by dbms_random.value

)
where rownum <= 20;

2.MS SQL Server,随机查询语句-20条

select top 20 * from 表名order by newid()

3.My SQL:,随机查询语句-20条

select * from 表名 order by rand() limit 20

select * from emp order by deptno desc limit0,2//查询支援信息,按部门编号倒序,截取前两个
select * from emp order by 1 desc limit0,2 (数字当前字段在临时表的位置)
select rand()随机返回0-1之间小数
select * from question order by 9 lomit0,4 #rand()0.5—>5 超过字段时会变成1

mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数


给包中的类名注册别名。 就可以不使用全限定名。 第二种方式 不推荐使用:如果有两个同名的类,就会出现错误。

***resultType
mybaris执行了sql语句,得到java对象。
1)resultType 结果类型,指sql语句执行完毕后,数据转为的java对象。
java类型是任意的,resultType结果类型的值:1.类型的全限定名称,2.别名
处理方式:
1.mybatis执行sql语句,然后mybatis调用类的无参数构造方法,创建对象。
2.mybatis把Result指定列值付给同名的属性。
<select id=selectMulitPositon" resultType=“com.anyu.domain.Studnet”>
select * from Student;

对等的jdbc
ResultSet rs=excuteQuery(“select * from student”)
while(rs.next()){
student student=new student();
student.setId(getInt(“id”);

}
简单类型:
接口方法:
int countStudent();
mapper 文件:

select count(*) from student

测试方法:
@Test
public void testRetunInt(){
int count = studentDao.countStudent();
System.out.println(“学生总人数:”+ count);
}
B、 对象类型
接口方法:
Student selectById(int id);
mapper 文件:

select id,name,email,age from student where id=#{studentId}

Map***
sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
接口方法:
返回的结果Mao
列名是:列名=列值 列名是map的key,列值是map的value
Map<Object,Object> selectReturnMap(int id);
mapper 文件:

select name,email from student where id = #{studentId}

测试方法:
@Test
public void testReturnMap(){
Map<Object,Object> retMap = studentDao.selectReturnMap(1002);
System.out.println(“查询结果是 Map:”+retMap);
}
3.3.2 resultMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。
常用在列名和 java 对象属性名不一样的情况。
使用方式:
表中是列名,实体表是属性,把列名付给属性名。
1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。
接口方法:
List selectUseResultMap(QueryParam param);
mapper 文件:

select id,name,email,age from student where name=#{queryName} or age=#{queryAge} 测试方法: @Test public void testSelectUseResultMap(){ QueryParam param = new QueryParam(); param.setQueryName("李力"); param.setQueryAge(20); List stuList = studentDao.selectUseResultMap(param); stuList.forEach( stu -> System.out.println(stu)); }

resultType和resultMap不能一起用,二选其一。

当列名和属性名不一致时。
(1) 使用列别名和
步骤:

  1. 创建新的实体类 PrimaryStudent
    package com.bjpowernode.domain;
    /**
  • Description: 实体类

  • Company: http://www.bjpowernode.com

*/
public class PrimaryStudent {
private Integer stuId;
private String stuName;
private Integer stuAge;
// set , get 方法
}2. 接口方法
List selectUseFieldAlias(QueryParam param);
3. mapper 文件:

select id as stuId, name as stuName,age as stuAge
from student where name=#{queryName} or age=#{queryAge}
4.测试方法
@Test
public void testSelectUseFieldAlias(){
QueryParam param = new QueryParam();
param.setQueryName(“李力”);
param.setQueryAge(20);
List stuList;
stuList = studentDao.selectUseFieldAlias(param);
stuList.forEach( stu -> System.out.println(stu));
}
北京动力节点 www.bjpowernode.com
(2) 使用
步骤:

  1. 接口方法
    List selectUseDiffResultMap(QueryParam param);
  2. mapper 文件:

type=“com.bjpowernode.domain.PrimaryStudent”>

select id,name,email,age from student where name=#{queryName} or age=#{queryAge} 3. 测试方法 @Test public void testSelectUseDiffResultMap(){ QueryParam param = new QueryParam(); param.setQueryName("李力"); param.setQueryAge(20); List stuList; stuList = studentDao.selectUseDiffResultMap(param); stuList.forEach( stu -> System.out.println(stu)); }

动态sql**
动态sql:sql的内容是变化的,可以根据条件获取到不同的sql语句。
主要是where部分发生改变。
动态sql的实现。使用的是mybatis提供的标签,
1)是判断条件的,语法部分sql语句
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法: sql 语句的部分
接口方法:
List selectStudentIf(Student student);
mapper 文件:

select id,name,email,age from student
where 1=1 在这里加上这个之后语法就会正确,如果不存在name的时候

and name = #{name}


and age > #{age}


测试方法:
@Test
public void testSelect() throws IOException {
Student param = new Student();
param.setName(“李力”);//设置java对象的属性值
param.setAge(18);
List studentList = studentDao.selectStudentIf(param);
studentList.forEach( stu -> System.out.println(stu));
}

动态 SQL 之
标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后
的所有条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL
出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会
严重影响查询效率。
使用标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加
where 子句。需要注意的是,第一个标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,
系统会将多出的 and 去掉。但其它中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错

语法: 其他动态 sql
接口方法:
List selectStudentWhere(Student student);
mapper 文件:

select id,name,email,age from student


and name = #{name}


and age > #{age}



测试方法:
@Test
public void testSelectWhere() throws IOException {
Student param = new Student();
param.setName(“李力”);
param.setAge(18);
List studentList = studentDao.selectStudentWhere(param);
studentList.forEach( stu -> System.out.println(stu));
}

4.4动态 SQL 之
标签用于实现对于数组与集合的遍历。对其使用,需要注意:
➢ collection 表示要遍历的集合类型, list ,array 等。
➢ open、close、separator 为对遍历内容的 SQL 拼接。
语法:

#{item 的值}

(1) 遍历 List<简单类型>
表达式中的 List 使用 list 表示,其大小使用 list.size 表示。
需求:查询学生 id 是 1002,1005,1006
接口方法:
List selectStudentForList(List idList);
北京动力节点 www.bjpowernode.com
mapper 文件:

select id,name,email,age from student

where id in

#{stuid}



测试方法:
@Test
public void testSelectForList() {
List list = new ArrayList<>();
list.add(1002);
list.add(1005);
list.add(1006);
List studentList = studentDao.selectStudentForList(list);
studentList.forEach( stu -> System.out.println(stu));
}(2) 遍历 List<对象类型>
接口方法:
List selectStudentForList2(List stuList);
mapper 文件:

select id,name,email,age from student

where id in

#{stuobject.id}


测试方法:
@Test
public void testSelectForList2() {
List list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002);
list.add(s1);
s1 = new Student();
s1.setId(1005);
list.add(s1);
List studentList = studentDao.selectStudentForList2(list);
studentList.forEach( stu -> System.out.println(stu));
}

5。动态 SQL 之代码片段
标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用
子标签。该标签可以定义 SQL 语句中的任何部分,所以子标签可以放在动态 SQL
的任何位置。
接口方法:
List selectStudentSqlFragment(List stuList);
mapper 文件:

select id,name,email,age from student

where id in #{stuobject.id} 测试方法: @Test public void testSelectSqlFragment() { List list = new ArrayList<>(); Student s1 = new Student(); s1.setId(1002); list.add(s1); s1 = new Student(); s1.setId(1005); list.add(s1); List studentList = studentDao.selectStudentSqlFragment(list); studentList.forEach( stu -> System.out.println(stu)); }

5.3 事务
(1) 默认需要手动提交事务
Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection
对象的 commit(), rollback() .
Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交、
该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。 ➢ JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法
回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对
事务进行提交或回滚。从日志的输出信息中可以看到。
MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。
(2) 自动提交事务
设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。
session = factory.openSession(true);
再执行 insert 操作,无需执行 session.commit(),事务是自动提交的
在 classpath 路径下,创建 properties 文件
在 resources 目录创建 jdbc.properties 文件,文件名称自定义。
(2) 使用 properties 标签
修改主配置文件,文件开始位置加入:
(3) 使用 key 指定值

5.5 typeAliases(类型别名) Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发,主要使用在 mybatis.xml 主配置文件定义别名: 北京动力节点 www.bjpowernode.com mapper.xml 文件,使用别名表示类型 select id,name,email,age from student 5.6 mappers(映射器) (1) 使用相对于类路径的资源,从 classpath 路径查找文件 例如: (2) 指定包下的所有 Dao 接口 如: 注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。

6.1.2 基于 PageHelper 分页:
实现步骤:
(1) maven 坐标

com.github.pagehelper
pagehelper
北京动力节点 www.bjpowernode.com
5.1.10
(2) 加入 plugin 配置
在之前加入


(3) PageHelper 对象
查询语句之前调用 PageHelper.startPage 静态方法。
除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。
在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个
方法后的第一个 MyBatis 查询方法会被进行分页。
@Test
public void testSelect() throws IOException {
//获取第 1 页,3 条内容
PageHelper.startPage(1,3);
List studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值