赞
踩
使用要求:
1、持久层接口(src\main\java\dao\IUserDao.java)和持久层接口的映射配置(src\main\resources\dao\IUserDao.xml)必须在相同的包下
2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
<mapper namespace="dao.IUserDao">
3、SQL 语句的配置标签,,,的 id 属性必须和持久层接口的
方法名相同。
持久层接口的方法
/**
* 查询所有数据
* @return
*/
List<User> findAll();
SQL 语句的配置标签id 属性
<select id="findAll" resultType="domain.User">
select * from user
</select>
关于测试类的一些细节:
package test; import bao;//此处是要导入的包,为了节约空间所以省略 public class MybatisTest { /** * 测试mybatis的CRUD操作 */ //全局属性用于实现对应操作 InputStream in; SqlSession sqlSession; IUserDao uesrdao; //before注释说明该方法最先执行相当于servlet中的init方法 //用于给对应对象赋值用于后续的增删改查操作 //这几个对象是通用的所以提出来 //也可以写工具类来实现 @Before public void init() throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory build = new SqlSessionFactoryBuilder().build(in); sqlSession = build.openSession(); uesrdao = sqlSession.getMapper(IUserDao.class); } //before注释说明该方法最后执行相当于servlet中的destory方法 //用于释放资源 @After public void destory() throws Exception { sqlSession.commit(); sqlSession.close(); in.close(); }
/**
* 根据id查询用户
* @param id
*/
User findById(int id);
<select id="findById" parameterType="int" resultType="domain.User">
select * from user where id=#{id}
</select>
细节:
resultType 属性:用于指定结果集的类型。
parameterType :用于指定传入参数的类型。
sql 语句中使用#{} 字符 :它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
.#{} 中内容的写法:由于数据类型是基本类型,所以此处可以随意写。
@Test
public void testFindOne(){
//通过id查找用户
User user = uesrdao.findById(48);
System.out.println(user);
}
/**
* 添加用户
* @param user
*/
void addUser(User user);
<insert id="addUser" parameterType="domain.User">
insert into user (username,address,sex,birthday) value (#{username},#{address},
#{sex},#{birthday})
</insert>
@Test
public void testAddUser(){
//添加用户
User user = new User();
user.setUsername("wf");
user.setAddress("中国");
user.setSex("男");
user.setBirthday(new Date());
//执行添加操作
uesrdao.addUser(user);
}
/**
* 添加用户
* @param user
*/
void addUser(User user);
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
@Test
public void testDeleteUser(){
//删除用户
uesrdao.deleteUser(49);
}
/**
* 更新用户
* @param user
*/
void updateUser(User user);
<update id="updateUser" parameterType="domain.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday}
</update>
@Test
public void testDeleteUser(){
//删除用户
uesrdao.deleteUser(49);
}
/**
* 模糊查询用户信息
* @return
*/
List<User> findByName(String str);
<select id="findByName" resultType="domain.User" parameterType="String">
<!--select * from user where username like '%${value}%'-->
<!-- 使用上面方式模糊查询时Statment对象通过字符串拼接的方式连接sql语句
下面的sql语句使用PrepatedStatement的参数占位符有预处理,
所以下面这种方式使用的多
-->
select * from user where username like #{str}
</select>
@Test
public void testAddUser(){
//添加用户
User user = new User();
user.setUsername("wf");
user.setAddress("中国");
user.setSex("男");
user.setBirthday(new Date());
//执行添加操作
uesrdao.addUser(user);
}
在控制台输出的执行 SQL 语句如下:
Preparing: select * from user where username like ?
我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标
识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”。
第一步:修改 SQL 语句的配置,配置如下:
<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like '%${value}%'
</select>
我们在上面将原来的#{}占位符,改成了 v a l u e 。 注 意 如 果 用 模 糊 查 询 的 这 种 写 法 , 那 么 {value}。注意如果用模糊查询的这种写法,那么 value。注意如果用模糊查询的这种写法,那么{value}的写法就是固定的,不能写成其它名字。
第二步:测试
/**
* 测试模糊查询操作
*/
@Test
public void testFindByName(){
//5.执行查询一个方法
List<User> users = userDao.findByName("王");
for(User user : users){
System.out.println(user);
}
}
在控制台输出的执行 SQL 语句如下:
Preparing: select * from user where username like ‘%王% ’
可以发现,我们在程序代码中就不需要加入模糊查询的匹配符%了,这两种方式的实现效果是一样的,但执行
的语句是不一样的。
我们一起来看 TextSqlNode 类的源码:
public String handleToken(String content) {
Object parameter = this.context.getBindings().get("_parameter");
if (parameter == null) {
this.context.getBindings().put("value", (Object)null);
} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
this.context.getBindings().put("value", parameter);
}
Object value = OgnlCache.getValue(content, this.context.getBindings());
String srtValue = value == null ? "" : String.valueOf(value);
this.checkInjection(srtValue);
return srtValue;
}
这就说明了源码中指定了读取的 key 的名字就是”value”,所以我们在绑定参数时就只能叫 value 的名字
了。
/**
* 添加用户
* @param user
*/
void addUser(User user);
<!-- 查询总记录条数 -->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
@Test
public void testFindTotal() throws Exception {
//6.执行操作
int res = userDao.findTotal();
System.out.println(res);
}
1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向sql语句传参数麻烦,因为sql语句的where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:Mybatis自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的
类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对
象解析比较方便。
解决:Mybatis自动将 sql执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的
类型。
我们在上一节中已经介绍了 SQL 语句传参,使用标签的 parameterType 属性来设定。该属性的取值可以
是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装
类,本节将介绍如何使用实体类的包装类作为参数传递。
基本类型和 String我们可以直接写类型名称 ,也可以使用包名 . 类名的方式 ,例如 :
java.lang.String。
实体类类型,目前我们只能使用全限定类名。
究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查
询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
package domain;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
/**
* 模糊查询用户信息
* @return
*/
List<User> findByVo(QueryVo vo);
<select id="findByVo" resultType="domain.User" parameterType="domain.QueryVo">
select * from user where username like #{user.username}
</select>
@Test
public void testFindByVo(){
//通过模糊查询查找用户
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%g%");
vo.setUser(user);
List<User> users = uesrdao.findByVo(vo);
for(User u:users){
System.out.println(u);
}
}
resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
我们在前面的 CRUD 案例中已经对此属性进行过应用了。
需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须
使用全限定类名。例如:我们的实体类此时必须是全限定类名(今天最后一个章节会讲解如何配置实体类的别名)
同时,当是实体类名称是,还有一个要求, 实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。
/**
- 查询总记录条数
- @return
*/
int findTotal();
<!-- 查询总记录条数 -->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
/**
* 查询所有用户
* @return
*/
List<User> findAll();
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
实体类代码如下:( 此时的实体类属性和数据库表的列名已经不一致了)
/**
*
* <p>Title: User</p>
* <p>Description: 用户的实体类</p>
*/
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
public Integer getUserId() {
return userId;
}
//此处自动生成get和set及tostring方法
/**
* 查询所有用户
* @return
*/
List<User> findAll();
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
}
结果:
User{userId=null, userName=‘gx’, userAddress=‘null’, userSex=‘null’, userBirthday=null}
User{userId=null, userName=‘gx’, userAddress=‘null’, userSex=‘null’, userBirthday=null}
User{userId=null, userName=‘gx’, userAddress=‘null’, userSex=‘null’, userBirthday=null}
User{userId=null, userName=‘gx’, userAddress=‘null’, userSex=‘null’, userBirthday=null}
为什么名称会有值呢?
因为:mysql 在 在 windows private String userName;
使用别名查询
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="com.itheima.domain.User">
select id as userId,username as userName,birthday as userBirthday,
sex as userSex,address as userAddress from user
</select>
运行结果:
User{userId=41, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=42, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=43, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=45, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
如果我们的查询很多,都使用别名的话写起来岂不是很麻烦,有没有别的解决办法呢?
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类
型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap type="com.itheima.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
}
运行结果:
User{userId=41, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=42, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=43, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
User{userId=45, userName=‘gx’, userAddress=‘中国’, userSex=‘女’, userBirthday=Mon Apr 15 21:28:56 CST 2019}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。