前言
就是用来操作数据库的
1.JDBC快速入门
注意在使用前一定要导入jar包
在模块那里新建目录,新建lib,粘贴复制jar包,我这个jar设置的是模块有效
package test1017;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class test {
public static void main(String[] args) throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url="jdbc:mysql://127.0.0.1:3306/test";//最后一个为数据库名?useSSL=false
String username="root";//用户名
String password="kl12151215";//密码
Connection conn=DriverManager.getConnection(url,username,password);
//获取sql对象
Statement stmt=conn.createStatement();
String sql="insert into emp3 values('bb',2)";//sql语句
//执行sql
int count=stmt.executeUpdate(sql);//executeUpdate只能用于INSERT、UPDATE、DELETE
System.out.println(count);
//释放资源
stmt.close();
conn.close();
}
}
就这样我们就可以操作了
2.JDBC之API
2.1DriverManager
作用就是
1.注册驱动
2.获取数据库连接
Connection conn=DriverManager.getConnection(url,username,password);
比如这个就是获取数据库连接
而这个forName,其实底层调的就是DriverManager的注册驱动作用
然后就是mysql5之后的驱动包,可以不用写注册驱动了
// Class.forName("com.mysql.cj.jdbc.Driver");
意思是把这个省略掉,也可以运行
然后就是链接的时候,如果链接的是本机的mysql服务器,而且默认端口号为3306.则就可以省略这两个不写
// String url="jdbc:mysql://127.0.0.1:3306/test";//最后一个为数据库名?useSSL=false
String url="jdbc:mysql:///test";//最后一个为数据库名
然后就是可以在后面写上useSSL=false,解决一些警告提示,但是高版本的没有警告提示
String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名
如果还要继续配置参数,加上&继续添加就可以了
2.2 Connection
Connection
1.就是获取执行的sql对象,已经用过了
2.就是事务管理
String sql1="insert into emp3 values('bb',2)";//sql语句
String sql2="insert into emp3 values('cc',1)";//sql语句
try {
//开始事务
conn.setAutoCommit(false);
//执行sql
int count1=stmt.executeUpdate(sql1);
int count2=stmt.executeUpdate(sql2);
System.out.println(count1);
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception e) {
conn.rollback();
e.printStackTrace();
}
conn.setAutoCommit(false);
就是开启事务,设置为false的意思就是需要手动提交事务,true就是自动提交事务
commit就是我们手动写的提交事务
至于回滚事务的话,如果出错了就抛异常吧,反正也不会真正执行的,都是假的执行,只有提交了才是真正的执行,抛到异常那里,在回滚,回滚的话,就算在自己这个用户也是无法看到变化的,不回滚的话,那么自己就会看到异常前的sql语句带来的变化
2.3 Statement
Statement有两个方法
stmt.executeUpdate()执行的是DML和DDL语句,返回值是语句影响的行数,一般来说,执行失败了,就会返回0,但是DDL中删除的操作,执行成功返回的也是0
stmt.executeQuery()执行的是DQL语句,就是查询语句,返回值是ResultSet
DML语句
Statement stmt=conn.createStatement();
String sql1="update emp3 set name ='cc' where name = 'aa' ";//sql语句
//开始事务
conn.setAutoCommit(false);
//执行sql
int count1=stmt.executeUpdate(sql1);
System.out.println(count1);
if(count1>0)
{
System.out.println("修改成功");
}
else {
System.out.println("修改失败");
}
再加上这个就更完美了
DDL语句
String sql1="create database aaaa ";//sql语句
返回1就是执行成功
String sql1="drop database aaaa ";//sql语句
而drop时,成功的返回值就是0
ResultSet就是stmt.executeQuery()的返回值
它指向的就是那个你打印出的那个表
它一开始指向的name那一行,然后它有方法
next()方法就是将指向的光标下移一行,然后就是返回值,如果为有效行的话,返回true,反之
xxx getXxx(参数) :这个就是获取数据
xxx:是数据类型,如:int getInt(参数) 表明你要获取的数据是int类型的
参数:可以是int,代表列的编号
或者String:代表列的名称
public class test {
public static void main(String[] args) throws Exception {
String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名
String username="root";//用户名
String password="kl12151215";//密码
Connection conn=DriverManager.getConnection(url,username,password);
//获取sql对象
Statement stmt=conn.createStatement();
String sql1="select * from emp3";//sql语句
//执行sql
ResultSet rs=stmt.executeQuery(sql1);
while(rs.next())
{
int id=rs.getInt(2);
String name=rs.getString(1);
System.out.println(id);
System.out.println(name);
System.out.println("----------------");
}
//释放资源
rs.close();//这下rs也要释放资源
stmt.close();
conn.close();
}
}
这样的话,我们定义一个类,就可以储存这些数据了
然后定义一个链表,就可以全部数据存储了
int id=rs.getInt("dep_id");
String name=rs.getString("name");
或者这样写也是一样的
2.4PreparedStatement
1.这个可以预编译sql语句,第二这个可以防止sql注入问题
sql注入问题就是你登录的时候,账号乱写,然后密码写入一些特定的sql语句,让我们登录成功
比如密码输入 'or ‘1’ = '1
sql注入演示
我们这里假设name就是用户,dep_id就是密码
String name="bb";//用户名
String dep_id="2";
String sql1="select * from emp4 where name='' and dep_id= '' ";
先这样
String sql1="select * from emp4 where name=' " +name+" ' and dep_id= ' " +dep_id+"' ";
再把name插进去,这样sql语句就写好了
String name="bb";//用户名
String dep_id="2";
String sql1="select * from emp4 where name='"+name+"'and dep_id= '"+dep_id+"'";//注意的是,就是空格不要太大,不然读不出来
ResultSet rs=stmt.executeQuery(sql1);
if(rs.next())
{
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
下面我们将pid_t换成 'or ‘1’ = '1
String dep_id="'or '1' = '1";
结果还是这样的
为什么呢
我们看看最后的sql语句就知道了
select * from emp4 where name='bb'and dep_id= ''or '1' = '1'
可以看出,因为’1’ = '1’始终为真,所以,这个sql语句就为真,所以就会打印出所有东西,所以就会登录正确
因为这个密码改变了sql语句的意思,所以登录成功了,所以我们引入PreparedStatement,就可以防止了
PreparedStatement演示
public class test {
public static void main(String[] args) throws Exception {
String url="jdbc:mysql:///test?useSSL=false";//最后一个为数据库名
String username="root";//用户名
String password="kl12151215";//密码
Connection conn=DriverManager.getConnection(url,username,password);
Statement stmt=conn.createStatement();
String name="bb";//用户名
String dep_id="'or '1' = '1";
// String dep_id="aa";
String sql1="select * from emp4 where name=? and dep_id=?";//首先密码和用户我们用?替代
//PreparedStatement对象通过conn获取
PreparedStatement pstmt=conn.prepareStatement(sql1);//这里要传入sql语句
pstmt.setString(1,name);
pstmt.setString(2,dep_id);//给?设置值
ResultSet rs=pstmt.executeQuery();//这里就不需要传sql了
if(rs.next())
{
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
rs.close();
stmt.close();
conn.close();
}
}
这样我们就解决了sql注入问题
它是怎么解决的呢
它其实是把单引号转义了,让它就是一个’'里面的一个正常的数据,不会产生’‘
select * from emp4 where name='bb' and dep_id= '\'or \1\ = \1';#'or '1' = '1
下面讲一下预编译的问题
sql语句在执行的过程中,会经历检查sql语法,编译sql,执行sql的步骤
而预编译就是我们在执行到PreparedStatement pstmt=conn.prepareStatement(sql1);的时候,就已经检查sql语法,编译sql了,后面设置?的时候,只需要替换执行sql就可以了
这样的话,我们执行两条sql语句的话,不用PreparedStatement 的话,我们就要走两遍检查sql语法,编译sql,执行sql
用了PreparedStatement ,检查sql语法,编译sql走一遍,,执行sql走两遍就可以了
但是要开启预编译的话,要输入useServerPreStmts=true
要设置这个
String url="jdbc:mysql:///test?useSSL=false&useServerPreStmts=true";
2.5 数据库连接池
数据库连接池就和线程池是一样的,允许程序重复使用一个现有的数据库链接,而不是重新在建立一个
这个就是配置文件
public class test {
public static void main(String[] args) throws Exception {
//导入jar包
//lib文件
//定义配置文件
//文件
//加载配置文件
Properties prop=new Properties();
prop.load(new FileInputStream("test1017/src/druid.properties"));//路径是相对路径
//获取连接池对象
DataSource dataSource= DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接
Connection connection=dataSource.getConnection();
System.out.println(connection);
}
}
一般来说,有了数据库连接池,我们就不需要自己手动去连接本地的数据库了,它自己会链接了,因为配置文件都写好了
3.实操
public class Brand {
String name;
String dep_id;
public String getName() {
return name;
}
public String getDep_id() {
return dep_id;
}
public void setName(String name) {
this.name = name;
}
public void setDep_id(String dep_id) {
this.dep_id = dep_id;
}
public Brand(String name, String dep_id) {
this.name = name;
this.dep_id = dep_id;
}
public Brand() {
}
}
定义一个类来存每行
定义一个链表来存整个表
public class test {
public static void main(String[] args) throws Exception {
//导入jar包
//lib文件
//定义配置文件
//文件
//加载配置文件
Properties prop=new Properties();
prop.load(new FileInputStream("test1017/src/druid.properties"));
//获取连接池对象
DataSource dataSource= DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接
Connection conn=dataSource.getConnection();
//sql
String sql="select * from emp4";
//获取pstmt
PreparedStatement pstmt=conn.prepareStatement(sql);
//设置?参数
//执行
ResultSet rs=pstmt.executeQuery();
//然后存储
}
}
这个是查询的操作,或者是填充的操作
添加操作
insert into emp4(name dep_id) values(?,?);//有id的话,不用写,因为是默认自增长的
修改数据
update emp4
set name=?,
dep_id=?
where id=?
删除
delete from emp4 where id=?
4. maven
maven是一个项目管理和构建的工具
它的项目结构,构建流程,还有依赖管理都是很统一的
下面讲一下maven的构建
给test添加resources
xml里面可以导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--当前项目的坐标-->
<groupId>com.itheima</groupId>
<artifactId>test1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--导入mysql的jar包-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<!--scope的意思是说明jar的作用范围,所以这样只有test,测试环境,可以用junit,不写这个就是默认全部范围的-->
</dependency>
</dependencies>
</project>
比如这样
然后就可以写代码了
在java里面新建软件包,然后建java类就可以了
CTRL+A是全选
5.MyBatis
5.1查询
drop table if exists tb_brand;
create table tb_brand
(
#主键
id int primary key auto_increment,
#品牌名称
brand_name varchar(20),
#企业名称
company_name varchar(20),
#排序字段
ordered int,
#描述信息
description varchar(100),
#状态 0:禁用 1:启用
status int
);
insert into tb_brand(brand_name,company_name,ordered,description,status)
values ('三只松鼠','三只松鼠股份有限公司',5,'好吃不上火',0),
('华为','华为技术有限公司',108,'华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界',1),
('小米','小米科技有限公司',50,'are you ok',1);
SELECT * FROM tb_brand;
package com.itheima.pojo;
public class Brand {
private int id ;
private String brand_name ;
private String company_name ;
private String ordered ;
private String description ;
private int status ;
public int getId() {
return id;
}
public String getBrand_name() {
return brand_name;
}
public String getCompany_name() {
return company_name;
}
public String getOrdered() {
return ordered;
}
public String getDescription() {
return description;
}
public int getStatus() {
return status;
}
public void setId(int id) {
this.id = id;
}
public void setBrand_name(String brand_name) {
this.brand_name = brand_name;
}
public void setCompany_name(String company_name) {
this.company_name = company_name;
}
public void setOrdered(String ordered) {
this.ordered = ordered;
}
public void setDescription(String description) {
this.description = description;
}
public void setStatus(int status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brand_name='" + brand_name + '\'' +
", company_name='" + company_name + '\'' +
", ordered='" + ordered + '\'' +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
package com.itheima.mapper;
import com.itheima.pojo.Brand;
import java.util.List;
public interface BrandMapper {
// 查询所有
public List<Brand> selectAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.UserMapper">
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<select id="selectAll" resultType="brand">
select *
from tb_brand;
</select>
</mapper>
public class MybatisTest {
//测试用例
@Test
public void testSelectAll() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);
//4.执行方法
List<Brand> brands=brandMapper.selectAll();
System.out.println(brands);
//5.释放资源
sqlSession.close();
//Mybatis完成操作三步,,,编写接口方法,编写sql,执行方法,,,,,,
}
}
如果我们Brand里面的名称为brandName
驼峰命名模式,那么就有可能查询不到
但是我们可以取别名
package com.itheima.pojo;
public class Brand {
private int id ;
private String brandName ;
private String companyName ;
private String ordered ;
private String description ;
private int status ;
public int getId() {
return id;
}
public String getbrandName() {
return brandName;
}
public String getcompanyName() {
return companyName;
}
public String getOrdered() {
return ordered;
}
public String getDescription() {
return description;
}
public int getStatus() {
return status;
}
public void setId(int id) {
this.id = id;
}
public void setbrandName(String brandName) {
this.brandName = brandName;
}
public void setcompanyName(String companyName) {
this.companyName = companyName;
}
public void setOrdered(String ordered) {
this.ordered = ordered;
}
public void setDescription(String description) {
this.description = description;
}
public void setStatus(int status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered='" + ordered + '\'' +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
比如这样,所有都变成了驼峰模式,但是数据库里面还是下划线的模式
所以找不到
我们可以用取别名的方法
在sql语句的配置文件那里
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间-->
<mapper namespace="com.itheima.mapper.BrandMapper">
<!--数据库表的字段名称和实体类的属性名称不一样,就不能自动封装数据,取别名就可以了-->
<select id="selectAll" resultType="brand">
select id ,brand_name as brandName,company_name as companyName,ordered,description,status
from tb_brand;
</select>
<!-- <select id="selectAll" resultType="brand">-->
<!-- select *-->
<!-- from tb_brand;-->
<!-- </select>-->
</mapper>
第一种方法是取别名,让别名和实体类的属性名一样就可以了
第二种方法就是定义sql片段
<sql id="brand_column">
id ,brand_name as brandName,company_name as companyName,ordered,description,status
</sql>
<select id="selectAll" resultType="brand">
select
<include refid="brand_column" />
from tb_brand;
</select>
缺点就是不灵活,确定了那么多个
接下来用resultMap
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select
*
from tb_brand;
</select>
brandResultMap随便取,是一个唯一标识
brand是类型,也就是别名com.itheima.pojo.Brand的,映射的类型,支持别名
result 是一般字段的映射
id column中id是对主键的映射
companyName是一般字段
column是表的列名
property实体类的属性名
1.定义标签
2.属性替换
5.2 查看详情
根据id查询详情
public interface BrandMapper {
// 查询所有
public List<Brand> selectAll();
//查看详情
Brand selectByIdBrand(int id);
}
<select id="selectByIdBrand" resultMap="brandResultMap">
select *
from tb_brand where id=#{id};
</select>
select id中的id和方法名是一样的
#{id}这个就相当于原来写的问号是一样的
{}里面的和方法的参数名称保持一致就可以了
@Test
public void testSelectById() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int id=1;
Brand brand=brandMapper.selectById(id);
System.out.println(brand);
//5.释放资源
sqlSession.close();
//Mybatis完成操作三步,,,编写接口方法,编写sql,执行方法,,,,,,
}
}
相比原来只需要改两行代码就可以了
而且这种测试方法,鼠标放在哪里,就运行哪个方法
#{id}就是?
这个就是参数占位符
参数占位符:
${}
#{}
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id=${id};
</select>
#{}替换为?,再给?赋值,,这个是为了防止SQL注入的
${}:直接替换为1,直接拼sql,存在SQL注入问题
所以用#{}
<select id="selectById" resultMap="brandResultMap">
select *
from ${tableName} where id=#{id};
</select>
${}用于表名和列名不固定的情况下
但还是存在SQL注入
<select id="selectById" parameterType="int" resultMap="brandResultMap">
select *
from tb_brand where id=#{id};
</select>
表示给#{id}设置为int类型
可以省略掉
因为接口那里就已经是int类型的了
因为<和插面的<冲突了
所以特殊字符的处理就是转义或者CDATA区
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id < #{id};
</select>
<这个就是<的转义
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id
<![CDATA[
<
]]>
#{id};
</select>
CDATA区直接CD然后提示就可以了
5.3 条件查询
select * from tb_brand where
就是输入多个条件,然后来查询
状态status=?
company_name=
写一个包含关键字的就可以查询,按理说
company_name like ?
这个是模糊查询
brand_name like ?
如何连接—》and
@Param(“status”)的意思就是int status中status就是要传递给占位符为status的,就是#{status}
第二个函数的意思就是,把这三个参数封装成一个对象,根据里面的getstatus方法,把对象里面的status,给status
所以参数的占位符名称要和brand对象里面的属性名称一样
不然找不到get方法
第三个就是封装成map集合
map集合键的名称要和参数占位符保持一致
<!-- 条件查询-->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
条件查询
1.散装参数 如果有多个参数,需要使用@Param(占位符名称),因为这样可以标记,特定去使用对应的sql语句的占位符
2.对象参数
3.map集合参数
List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
@Test
public void testSelectByCondition() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="华为";
String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
List<Brand> brands=brandMapper.selectByCondition(status,brandName,companyName);
System.out.println(brands);
//5.释放资源
sqlSession.close();
}
List<Brand> selectByCondition(Brand brand);
@Test
public void testSelectByCondition() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="华为";
String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
Brand brand=new Brand();
brand.setStatus(status);
brand.setbrandName(brandName);
brand.setcompanyName(companyName);
List<Brand> brands=brandMapper.selectByCondition(brand);
System.out.println(brands);
//5.释放资源
sqlSession.close();
}
List<Brand> selectByCondition(Map map);
@Test
public void testSelectByCondition() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="华为";
String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
// Brand brand=new Brand();
// brand.setStatus(status);
// brand.setbrandName(brandName);
// brand.setcompanyName(companyName);
Map map=new HashMap();
map.put("status",status);//保证map键的名称和参数占位符的名称一样
map.put("companyName",companyName);
map.put("brandName",brandName);
//List<Brand> brands=brandMapper.selectByCondition(brand);
List<Brand> brands=brandMapper.selectByCondition(map);
System.out.println(brands);
//5.释放资源
sqlSession.close();
}
如果只想查询一个,我们只设置一个
Map map=new HashMap();
map.put("status",status);//保证map键的名称和参数占位符的名称一样
// map.put("companyName",companyName);
// map.put("brandName",brandName);
那么就会查不出来
因为我们的sql语句查的是三个,有两个的值都没有设置,都是null,所以数据查不出来了,所以不灵活
所以如何动态查询呢
就是sql语句会随着用户的输入或者外部条件的变化而变化,我们称之为动态sql
如何判断用户输入没有呢,如果用户输入了,就不是null,就查询
所以这样来 if(status!=null)status=#{status}
这就是动态sql
mybatis很支持动态sql
它有很多标签支持
<!-- 动态条件查询-->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
<if test="status !=null">
status = #{status}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="companyName!=null and companyName!='' ">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName}
</if>
</select>
Map map=new HashMap();
map.put("status",status);//保证map键的名称和参数占位符的名称一样
map.put("companyName",companyName);
map.put("brandName",brandName);
Map map=new HashMap();
map.put("status",status);//保证map键的名称和参数占位符的名称一样
map.put("companyName",companyName);
// map.put("brandName",brandName);
Map map=new HashMap();
// map.put("status",status);//保证map键的名称和参数占位符的名称一样
map.put("companyName",companyName);
// map.put("brandName",brandName);
但是这样就会报错
因为第一个status没了,导致sql语句的where后面直接接上了and,所以出错了,sql语法有错
处理方法就是每个if都加and,然后where后面有缓冲,就是有一个恒等式
<!-- 动态条件查询-->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where 1=1
<if test="status !=null">
and status = #{status}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="companyName!=null and companyName!='' ">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName}
</if>
</select>
看这个1=1,其实一点用都没有,就是为了满足语法而已
Map map=new HashMap();
// map.put("status",status);//保证map键的名称和参数占位符的名称一样
map.put("companyName",companyName);
// map.put("brandName",brandName);
但这个方法mbatis早就想好了,可以用where标签来替换where关键字
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="status !=null">
and status = #{status}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="companyName!=null and companyName!='' ">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName}
</if>
</where>
</select>
用where关键字的时候,如果里面只有一个条件,那么就会自动取消and,这就是它的作用
5.4 单条件动态查询
就是用户自己选择条件查询,只针对某一个条件查询,针对这个条件输入自己的关键字
这里choose就相当于switch
when就是case
otherwise就是default
//单条件动态查询
List<Brand> selectByConditionSingle(Brand brand);//brand对象的作用就是哪个属性有值的话,就用哪个
</select>
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose>
<when test="status!=null">
status=#{status}
</when>
<when test="companyName!=null and companyName!=''">
company_name like #{companyName}
</when>
<when test="brandName!=null and brandName!=''">
brand_name like #{brandName}
</when>
</choose>
</select>
@Test
public void testSelectByConditionSingle() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="华为";
String brandName="华为";//这样是不行的,因为期待的是,用户输入了华为,就进行模糊匹配,所以要写模糊的表达式,用%或者_,在程序里面处理
companyName="%"+companyName+"%";
brandName="%"+brandName+"%";
Brand brand=new Brand();
brand.setStatus(status);
// brand.setbrandName(brandName);
//brand.setcompanyName(companyName);
//List<Brand> brands=brandMapper.selectByCondition(brand);
List<Brand> brands=brandMapper.selectByConditionSingle(brand);
System.out.println(brands);
//5.释放资源
sqlSession.close();
}
Brand brand=new Brand();
brand.setStatus(status);
// brand.setbrandName(brandName);
//brand.setcompanyName(companyName);
但万一用户一个都不选呢
Brand brand=new Brand();
// brand.setStatus(status);
// brand.setbrandName(brandName);
//brand.setcompanyName(companyName);
这样就可能会出错,因为一个都没选的话,where后面就没有内容了
所以用default
</select>
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose>
<when test="status!=null">
status=#{status}
</when>
<when test="companyName!=null and companyName!=''">
company_name like #{companyName}
</when>
<when test="brandName!=null and brandName!=''">
brand_name like #{brandName}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>
这里where1=1,单纯是为了满足语法
也可以这样
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose>
<when test="status!=null">
status=#{status}
</when>
<when test="companyName!=null and companyName!=''">
company_name like #{companyName}
</when>
<when test="brandName!=null and brandName!=''">
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
用where标签,和上面就是一模一样的了
5.5 添加
//添加
void add(Brand brand);
这里更改一下,status是int类型
<insert id="add">
insert into tb_brand(brand_name,company_name,ordered,description,status)
values(#{brandName},#{companyName},#{ordered},#{description},#{status})
</insert>
@Test
public void testAdd() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="波导手机";
String brandName="波导";
String description="手机中的战斗机";
int ordered=100;
Brand brand=new Brand();
brand.setStatus(status);
brand.setbrandName(brandName);
brand.setcompanyName(companyName);
brand.setDescription(description);
brand.setOrdered(ordered);
brandMapper.add(brand);
//5.释放资源
sqlSession.close();
}
但是数据库里面并没有添加
为什么呢
因为mybatis给你关闭了事务的自动提交,所以你要手动提交才行
@Test
public void testAdd() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int status=1;
String companyName="波导手机";
String brandName="波导";
String description="手机中的战斗机";
int ordered=100;
Brand brand=new Brand();
brand.setStatus(status);
brand.setbrandName(brandName);
brand.setcompanyName(companyName);
brand.setDescription(description);
brand.setOrdered(ordered);
brandMapper.add(brand);
//提交事务
sqlSession.commit();
//5.释放资源
sqlSession.close();
}
如果不想手动提交事务的话
可以这样
//2.获取SqlSession对象
//SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
true这样就是自动提交了
openSession是默认开启事务的
5.6 主键返回
brandMapper.add(brand);
Integer id=brand.getId();
System.out.println(id);
注意这里的id应该改为Integer,不然默认为0
这里打印出来就是null
所以数据库添加成功之后,数据库里面的id值无法获取出来
但是这里数据里里面是有数据的
但是得不到id
如何把数据库里面的id绑定到对象里面呢
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand(brand_name,company_name,ordered,description,status)
values(#{brandName},#{companyName},#{ordered},#{description},#{status})
</insert>
我们可以设置一个useGeneratedKeys为true
然后一个keyProperty为order对象里面主键id的名称
设置完这个,对象里面就有id值了
brandMapper.add(brand);
Integer id=brand.getId();
System.out.println(id);
这就是主键返回
5.7 修改全部字段
就是点击编辑按钮的时候,然后就可以对所有的数据更改
<update id="update">
update tb_brand
set
brand_name=#{brandName},
company_name=#{companyName},
ordered=#{ordered},
description=#{description},
status=#{status}
where id=#{id};
</update>
int update(Brand brand);
@Test
public void testUpdate() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
//SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int id=5;//修改第五个
int status=1;
String companyName="波导手机";
String brandName="波导";
String description="波导手机,手机中的战斗机";
int ordered=200;
Brand brand=new Brand();
brand.setStatus(status);
brand.setbrandName(brandName);
brand.setcompanyName(companyName);
brand.setDescription(description);
brand.setOrdered(ordered);
brand.setId(id);
int count=brandMapper.update(brand);
System.out.println(count);
//提交事务
sqlSession.commit();
//5.释放资源
sqlSession.close();
}
5.8 修改动态字段
意思是有很多的数据,只定向的修改几个就可以了
比如修改密码,那么就只提交密码和id就可以了
如果用原来的sql语句,只提交了几个,那么其他几个就变成null了
Brand brand=new Brand();
Brand brand=new Brand();
brand.setStatus(status);
// brand.setbrandName(brandName);
// brand.setcompanyName(companyName);
// brand.setDescription(description);
// brand.setOrdered(ordered);
brand.setId(id);
我们看这个,只提交id和status
<update id="update">
update tb_brand
set
<if test="brandName!=null and brandName!=''">
brand_name=#{brandName},
</if>
<if test="companyName!=null and companyName!=''">
company_name=#{companyName},
</if>
<!-- 因为ordered是Integer,所以不会为空字符串,只会为null-->
<if test="ordered!=null">
ordered=#{ordered},
</if>
<if test="description!=null">
description=#{description},
</if>
<if test="status!=null">
status=#{status}
</if>
where id=#{id};
</update>
这个有一点问题,第一个就是逗号的问题,如果最后一句没有执行,那么where前面就会有一个逗号
第二个就是如果全部if都没有执行,那么只有set了
这两个问题可以用set标签
<update id="update">
update tb_brand
<set>
<if test="brandName!=null and brandName!=''">
brand_name=#{brandName},
</if>
<if test="companyName!=null and companyName!=''">
company_name=#{companyName},
</if>
<!-- 因为ordered是Integer,所以不会为空字符串,只会为null-->
<if test="ordered!=null">
ordered=#{ordered},
</if>
<if test="description!=null">
description=#{description},
</if>
<if test="status!=null">
status=#{status}
</if>
</set>
where id=#{id};
</update>
//4.执行方法
int id=6;//修改第五个
int status=0;
String companyName="波导手机";
String brandName="波导";
String description="波导手机,手机中的战斗机";
int ordered=200;
Brand brand=new Brand();
brand.setStatus(status);
// brand.setbrandName(brandName);
// brand.setcompanyName(companyName);
// brand.setDescription(description);
// brand.setOrdered(ordered);
brand.setId(id);
5.9 删除功能
根据id把数据删除掉
//根据id删除
void deleteById(int id);
<delete id="deleteById">
delete from tb_brand where id=#{id};
</delete>
@Test
public void testDeleteById() throws IOException {
//1.获取SqlSessionFactory//不用写,自己复制
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象
//SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int id=6;//修改第五个
brandMapper.deleteById(id);
//提交事务
sqlSession.commit();
//5.释放资源
sqlSession.close();
}
5.10 批量删除
就是直接删除多个数据
就是选中多个,然后一起删除,这就是复选框
就是给的多个id删除,分装成id数组,传进去就可以了
但是?占位符应该写几个呢,所以应该是动态sql,要有几个id,所以要遍历这个数组,用foreach
collection表示你要遍历哪个数组
item就是遍历出来的每一个元素
#{id}为占位符
那么遍历几次,就有几个?
这样就可以了
//批量删除
void deleteByIds(int[]ids);
<delete id="deleteByIds">
delete from tb_brand where id
in (?,?,?);
</delete>
按理说应该这样写,写很多个问号,但是有几个?呢,遍历一下就知道了
<delete id="deleteByIds">
delete from tb_brand where id
in (
<foreach collection="ids"></foreach>
);
</delete>
但这里不能直接写ids,因为mybatis会将数组参数分装成一个Map集合
默认:key的名称是array,val就是这个数组
所以我们要array来获取数组
<delete id="deleteByIds">
delete from tb_brand where id
in (
<foreach collection="array"></foreach>
);
</delete>
或者也可以这样,用@Param来改变map集合默认key的名称
//批量删除
void deleteByIds(@Param("ids") int[]ids);
<delete id="deleteByIds">
delete from tb_brand where id
in (
<foreach collection="ids"item="id">
#{id}
</foreach>
);
</delete>
如果数组里面有三个id,那么就会生成三个#{id},那么就会被替换成?
而且之间应该有逗号隔开
<delete id="deleteByIds">
delete from tb_brand where id
in (
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
);
</delete>
separator就是分隔符的意思,我们用逗号分隔开
//4.执行方法
int[] ids={5,7,8};
brandMapper.deleteByIds(ids);
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
这样写的话,in就不用写括号了
下面演示一下array
//批量删除
void deleteByIds(int[]ids);
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
这样写也是可以的
没写@,就不要写ids
反正就这两种方法
5.11 参数传递
传了多个参数,那么就要用@Param
要和参数的占位符名称一样
如果为多个参数的话,会分装为map集合
把这些参数一个一个装到map里面
值就是参数名
键就是这样的
map.put(“arg0”,参数值1)
map.put(“param1”,参数值1)
map.put(“arg1”,参数值2)
map.put(“param2”,参数值2)
List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
List<Brand> brands=brandMapper.selectByCondition(status,companyName,brandName);
System.out.println(brands);
List<Brand> selectByCondition(int status,String companyName,String brandName);
如果去掉@Param就会出错
他说我们可以用[arg2, arg1, arg0, param3, param1, param2]
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="status !=null">
and status = #{status}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="companyName!=null and companyName!='' ">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName}
</if>
</where>
</select>
改为
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="arg0 !=null">
and status = #{arg0}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="arg1!=null and arg1!='' ">
and company_name like #{arg1}
</if>
<if test="arg2!=null and arg2!=''">
and brand_name like #{arg2}
</if>
</where>
</select>
然后就是parame1,也是可以的这些
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="param1 !=null">
and status = #{param1}
</if>
<!-- test里面的companyName就是 #{companyName}里面的companyName-->
<if test="param2!=null and param2!='' ">
and company_name like #{param2}
</if>
<if test="param3!=null and param3!=''">
and brand_name like #{param3}
</if>
</where>
</select>
但是并不推荐上面两种方法,还是建议使用@Param,这个就是来替换arg0,agr1,只对第一个参数@Param,那么arg0就被替换了,而且不能使用了,以此类推
单个参数的话,如果是POJO类型,可以直接使用,属性名和参数占位符一样,不用@Param
Map集合键名和参数占位符一样就可以了,直接使用,,不用@Param
其他类型:比如定义一个intid类型,也可以直接用
Collection:建立一个map,键就是collection,值就是你传进来的
还有一个键是arg0
List也是一样的,map有三个键,Collection,arg0,list
数组的话,键就是array和arg0
但是只要你全部用@Param(修改arg0),就没有事了
5.12 注解完成增删改查
就是把sql语句写在注解中,而不是配置文件
意思就是方法和sql语句挨在一起了
有四个注解
但是一般只完成简单功能,复杂功能还是用配置文件
比如动态sql还是写在配置文件中好点
User selectById(int id);
用这个的注解的前提就是相关的配置要注释掉
<!-- resultType是别名,大小写无所谓 -->
<!-- <select id="selectById" resultType="User">-->
<!-- select * from tb_user where id =#{id};-->
<!-- </select>-->
@Select("select * from tb_user where id = #{id}")
User selectById(int id);
User users=userMapper.selectById(3);
System.out.println(users);