探究
关于update、delete、insert一定要看这篇文章Mybatis系列第6篇:恕我直言,mybatis增删改你未必玩得转!
parameterType
parameterType:接口中方法参数的类型,类型的完全限定名或别名。这个属性是可选的,因为Mybatis可以推断出具体传入语句的参数,默认值为为设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句。
1、创建一个maven项目。
2、引入mybatis、junit、mysql的依赖
3、在src\main\java下,创建com.yongbin.dao
、·com.yongbin.domain、创建·com.yongbin.utils
三个包。
首先在com.yongbin.dao创建一个通过学生的id查询学生信息的方法。
/**
* 操作mybatis中的student表
* @author 刘瘦瘦
* @create 2021-07-13-15:38
*/
public interface StudentDao {
/**
*查询学生信息
*/
public Student selectStudentById(int id);
}
在com.yongbin.dao
目录下创建sql映射文件(mapper文件):
mapper文件的要求
:
- 作用:mapper文件是写sql语句的。一般一个表一个sql映射文件。这个文件是xml文件。
- 该文件写在接口所在的目录中(和StudentDao在同一个目录)
- 文件的名称和接口保持一致。
StudentDao.xml中的配置如下:
<!--
namespace:要写你的接口的权限定路径
-->
<!--
namespace:要写你的接口的权限定路径
-->
<mapper namespace="com.yongbin.dao.StudentDao">
<!--
1.id:要写你的接口中的方法名
2.parameterType:接口中方法参数的类型,可以使用mybatis提供的别名
也可以是数据类型的全限定路径。
parameterType不是强制的,mybatis通过反射机制能够发现接口参数的类型。,所以可以不写,我们一般也不写
3.reuresultType要和调用方法的返回值是一样的。
它有两种形式:1. 类型的全限定名称(建议) 2. 类型的别名, 例如 java.lang.Integer别名是int
4.sql语句中的#{sid},是占位符的意思,就是把调用的dao中的方法的参数传递给下面的占位符,当dao中的方法
是一个参数时,这里的名字可以随意起。如#{dog},#{dogleg},#{mary}
5.
-->
<select id="selectStudentById" parameterType="Integer" resultType="com.yongbin.domain.Student">
select * from student where id=#{sid}
</select>
</mapper>
运行当然可以运行,这里偷个懒。
MyBatis 传递参数
从 java 代码中把参数传递到 mapper.xml 文件。
mybatis的主配置文件,mybatis.xml的内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--环境配置:数据库的连接信息
default:必须和某个environment的id值一样。
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="mydev">
<environment id="mydev">
<!--
transactionManager:mybatis的事务类型
type:JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型,POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver、url、username、password是固定的,不能自定义。
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--
一个mapper标签指定一个文件的位置。
从类路径开始的路径信息。 target/clasess(类路径):
-->
<mapper resource="com/yongbin/dao/StudentDao.xml"/>
<!--可以配置多个-->
<!--<mapper resource="com/yongbin/dao/StudentDao.xml"/>-->
</mappers>
</configuration>
StudentDao的内容如下:
/**
* 操作mybatis中的student表
* @author 刘瘦瘦
* @create 2021-07-13-15:38
*/
public interface StudentDao {
/**
*查询学生信息,测试mapper文件中的parameterType
* parameterType:接口中方法参数的类型,可以使用mybatis提供的别名也可以是数据类型的全限定路径。
parameterType不是强制的,mybatis通过反射机制能够发现接口参数的类型。,所以可以不写,我们一般也不写
*/
public Student selectStudentById(int id);
/**
* 以下测试mybatis传递参数:从java代码中把参数传递到mapper.xml文件
*/
public Student selectStudentById2(int id);
/**
* 测试多个参数使用:@Param
* 当dao接口方法中有多个参数,需要通过名称使用参数。在方法形参前加入@Param("自定义参数名")
* mapper文件中使用#{"自定义参数名"}
*/
public List<Student> selectMultiParam(@Param("dogleg") String name,@Param("catleg") int id);
/**
* 多个参数--使用对象:
* 使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }
*/
public int selectStudentCountByObject(Student student);
/**
*多个参数--按位置
* 参数位置从0开始,引用参数语法#{arg位置}
* 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
*/
public Student selectStudentByPos(int id,String name);
/**
* 多个参数--使用Map
* Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,
Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。
*/
public List<Student> selectMultiParamByMap(Map<String,Object> map);
}
测试方法如下:
/**
* @author 刘瘦瘦
* @create 2021-07-13-16:06
*/
public class testStudentDao {
//测试ParametType
@Test
public void testParamType() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
Student student = stuImpl.selectStudentById(1003);
System.out.println(student);
}
/*
mybatis传递参数:1 简单类型 dao接口中的参数只有一个简单类型(java基本类型和String类型)
#{任意字符,和方法的参数名无关}
*/
@Test
public void testSelectStudentById2() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
Student student = stuImpl.selectStudentById2(1003);
System.out.println(student);
}
/*
mybatis传递参数:2 多个参数,自定义 :@Param("自定义参数名")
*/
@Test
public void testSelectMultiParam() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
List<Student> studentList = stuImpl.selectMultiParam("galigaygay", 1003);
for(Student stu:studentList){
System.out.println(stu);
}
}
/**
* 多个参数--使用对象:
*/
@Test
public void testSelectStudentCountByObject() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
int count=stuImpl.selectStudentCountByObject(new Student(1003,"galigaygay","galigaygay.@qq.com",23));
System.out.println(count);
}
/**
* 多个参数--使用位置:
*/
@Test
public void testSelectStudentByPos() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
Student student = stuImpl.selectStudentByPos(1002,"lisi");
System.out.println(student);
}
/**
* 多个参数--使用map:
*/
@Test
public void testSelectMultiParamByMap() throws IOException {
//获取SQLSession对象
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
//获取StudentDaoImpl对象
StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
//执行方法
Map<String,Object> map=new HashMap<>();
map.put("myname","galigaygay" );
map.put("myage",22 );
List<Student> students = stuImpl.selectMultiParamByMap(map);
students.forEach(System.out::println);
}
}
#和$的区别
#占位符
:告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql语句,#{…}代替sql语句的·?·。这样做更安全,更迅速,通常也是首选做法。
如下面的StudentDao.xml(mapper文件)的声明:
<select id="selectMultiParam4" resultType="com.yongbin.domain.Student">
select id,name,email,age from student where id=#{myId} or name=#{myName};
</select>
当运行时,转换为的sql语句为:
相当于执行的是:
String sql="select id,name,email,age from student where id=? or name=?
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,1005);
ps.setString(2,"lisi");
解释:where id=? or name=?就是 where id=#{myid} or name=#{myname}
ps.setInt(1,1005),1005会替换掉#{myid}等
$字符串替换
告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和 ${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
如下面的在StudentDao中定义的方法:
List<Student> selectUse$(@Param("myname") String name);
StudentDao.xml中的配置如下:
<!--
$作为占位符,会引起sql注入
-->
<select id="selectUse$" resultType="com.yongbin.domain.Student">
select id,name,email,age from student where name=${myname}
</select>
相当于:
上述结果发生了sql注入的问题。
封装Mybatis输出结果
returnType
returnType:执行sql得到的ResultSet转换的类型,使用类型的完全限定名(建议使用)或别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType和resultMap,不能同时使用。
简单类型
在StudentDao中定义如下的方法:
//查询表中的总记录数
int countStudent();
mapper文件(StudentDao.xml)中:
<!--
resultType要和调用方法的返回值是一样的。
它有两种形式:1. 类型的全限定名称(建议) 2. 类型的别名, 例如 java.lang.Integer别名是int--这是mybatis定义的
<select id="countStudent" resultType="int">
这里的int使用的是别名,更多别名参考官方文档
-->
<select id="countStudent" resultType="java.lang.Integer">
select count(*) from student
</select>
测试方法如下:
//resultType结果类型的它值 1. 类型的全限定名称 2. 类型的别名, 例如 java.lang.Integer别名是int
@Test
public void testCountStudent() throws IOException {
/**
* 使用mabtis的动态代理机制,使用SqlSession.getMapper(dao接口)
* getMapper能获取dao接口对应的实现类对象
*/
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
System.out.println(dao.countStudent());
}
在上面的apper.xml中,我们使用了官方的别名int代替了全限定路径java.lang.Integer,尽然可以使用官方定义的别名,那么我们可不可以自己定义别名呢?当然可以,在下面的语句上,使用别名。
<select id="selectMultiParam2" resultType="com.yongbin.domain.ViewStudent">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
如何自定义别名来用更少的字母代替"com.yongbin.domain.ViewStudent",可以共有两种方式,需要在mybatsi.xml(主配置文件中进行配置)
alias的汉语意思就是别名的意思。
<!--定义别名:方式一-->
<typeAliases>
<!-- 第一种方式
可以指定一个类型,一个自定义的别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆)
一个<typeAlias>定义一个类型的别名
-->
<!--<typeAlias type="com.yongbin.domain.Student" alias="stu"></typeAlias>-->
<!--<typeAlias type="com.yongbin.domain.ViewStudent" alias="vstu"></typeAlias>-->
<!--第二种方式
<package> name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<package name="com.yongbin.domain"></package>
</typeAliases>
但是使用第二种方式会发生冲突问题
比如现在有两个包:
com.yongbin.domain
com.yongbin.vo 两个包下面都有Student类,而mybatis中的
<typeAliases>
<package type="com.yongbin.domain" ></package>
<package type="com.yongbin.vo" ></package>
</typeAliases>
那么:这样就会冲突
<select id="selectMultiParam2" resultType="Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
建议还是使用全限定路径。
B对象类型
在StudentDao中定义如下的方法:
public Student selectStudentById(Integer id);
StudentDao.xml文件的配置如下:
mybatis在组建对象时,实体类可以没有set、get方法,但是必须和数据库中的字段名字一样(大小写均可)
比如:数据库中的字段是age 你的实体类中的可以是Age、AGE ,但是不能是其他:如safsdaf
<select id="selectStudentById" resultType="com.yongbin.domain.Student">
select id,name,email,age from student where id=#{id}
</select>
注意:Dao接口方法返回是集合类型,需要指定集合中的类型,不是集合本身
Map类型
在StudentDao中声明的抽象方法为:下面演示的是,返回一行的map形式,和返回多行的map形式。
//返回map的形式
Map<Object,Object> returnMapFormById(@Param("myid")int id);
//多行数据以map的形式返回
List<Map<Object,Object>> returnMapFormMultiLines(@Param("myid")int id);
mapper(StudentDao.xml)中的配置如下:
<!--返回map
1、列名是map的key,列值是map的value
2.下面的只能返回一行数据
3.多行数据以map的形式返回,见下面例子
-->
<select id="returnMapFormById" resultType="java.util.Map">
select * from student where id=#{myid}
</select>
<!-- 3.多行数据以map的形式返回,见下面例子-->
<select id="returnMapFormMultiLines" resultType="java.util.Map">
select * from student where id >#{myid}
</select>
//测试map--单行
@Test
public void testReturnMapForm() throws IOException {
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Map<Object, Object> maps = studentDao.returnMapFormById(1003);
System.out.println(maps);
}
//测试map--多行
@Test
public void testReturnMapFormMultiLines() throws IOException {
SqlSession sqlSession = MyBaitsUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Map<Object, Object>> maps = studentDao.returnMapFormMultiLines(1001);
System.out.println(maps);
}
测试单行的结果:
测试多行的结果:
mybatis在组建对象时,实体类可以没有set、get方法,但是必须和数据库中的字段名字一样(大小写均可)
比如:数据库中的字段是age 你的实体类中的可以是Age、AGE ,但是不能是其他:如safsdaf,解决这个问题可以使用returnMap和别名的方式。
returnMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。常用在列名和 java 对象属性名不一样的情况
基本使用方式举例::
- 先定义resultMap,指定列名和属性的对应关系。
- 在、等中把resultType替换为resultMap。
接口中定义的方法如下:
//使用resultMap定义映射关系
List<Student> selectAllStudents();
StudentDao.xml中的定义如下:
<!--
定义resultMap
id:自定义名称,表示你定义的这个resultMap
type:java类型的全限定名称
-->
<resultMap id="studentMap" type="com.yongbin.domain.Student">
<!--列名和java属性的关系-->
<!--主键列,使用id标签
column:列名
property:java类型的属性名
-->
<id column="id" property="id"></id>
<!--非主键列,使用result-->
<result column="name" property="name"></result>
<result column="email" property="email"></result>
<result column="age" property="age"></result>
<!--使用resultMap的话,必须要提供set方法-->
<!--这个resultMap可以被复用-->
</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
select * from student
</select>
解决数据库的字段名和实体类中的属性不一致的问题::
我们上述演示的Student类中的属性都和数据库表中的字段名一致:
下面我们重新定义一个MyStudent实体类,它和数据库表中的字段名不一样。
现在使用resultMap来解决。StudentDao中定义如下的方法:
StudentDao.xml中的声明如下:
<!--列名和属性名不一致怎么办?
方式一:使用上面的resultMap
-->
<resultMap id="mystudent" type="com.yongbin.domain.MyStudent">
<id column="id" property="stuid"></id>
<result column="name" property="stuname"></result>
<result column="email" property="stuemail"></result>
<result column="age" property="stuage"></result>
</resultMap>
<select id="selectAllMyStudents" resultMap="mystudent">
select * from student;
</select>
测试方法如下:
/*
resultMap:结果映射,指定列名和java对象的属性对应关系。
1.你自定义列值赋值给哪个属性
2.当你的列名和属性名不一样时,一定是要resultMap
*/
@Test
public void testSelectAllStudents() throws IOException {
SqlSession sqlSession=MyBaitsUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<MyStudent> MyStudent = studentDao.selectAllMyStudents();
for(MyStudent student :MyStudent){
System.out.println(student);
}
}
运行结果:
方法二,解决列名和属性名不一致问题,使用别名
StudentDao中的声明如下:
//表中的字段名和类中的属性名不一致,该怎么办?方式二:使用别名
//因为mybatis创建对象为其赋值时,是根据字段名和类中的属性名的一致来进行的
List<MyStudent> selectAllMyStudents2();
StudentDao.xml中的配置:
<!--列名和属性名不一致怎么办?
方式二:使用别名
-->
<select id="selectAllMyStudents2" resultType="com.yongbin.domain.MyStudent">
select id as stuid,name as stuname,email as stueamil,age as stuage from student;
</select>
测试方法:
/*
列名和属性名不一致怎么办?
方式二:sql语句使用别名
*/
@Test
public void testSelectAllMyStudents2() throws IOException {
SqlSession sqlSession=MyBaitsUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<MyStudent> students = studentDao.selectAllMyStudents2();
for(MyStudent student :students){
System.out.println(student);
}
}
运行结果:
模糊查询
模糊查询的实现有两种方式,一是java代码中给查询数据加上%
;二是在mapper文件sql语句的条件位置上加%
要求:查询姓名有“力”的
例子1、java代码中提供要查询的%力
接口中的方法:
例子2、mapper 文件中使用 like name "%" #{xxx} "%"
mybatis对parameterType和resultType定义的别名
系统已定义的别名直接在xml中文件中引用别名就可,不需要再写对应的全称类名,减少代码的书写量