Mybatis第二天
回顾Mybatis入门程序
mybatis实现增删改查
a、mybatis 的中文文档网址:http://www.mybatis.org/mybatis-3/zh/getting-started.html
b、 selectList 查询多个对象,返回一个list集合(也能查询一个)
selectOne: 查询单个对象,返回一个对象
c、日志记录日常操作
引入依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
引入日志的配置文件:log4j.properties
d、增删改查
<!--UserMapper删除操作-->
<delete id="del" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<!--测试类-->
@Test
public void testDel(){
//获取输入流对象
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象
//获取的sqlsession默认不能自动提交
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
sqlSession.delete("userMapper.del",3);
//提交:只要修改了数据库必须提交不然报错
sqlSession.commit();
sqlSession.close();
}
代码较集中,后续将用Dao开发
${}和#{}区别
e、模糊查询
参数: %a%
配置文件: username like #{username}
参数: a
配置文件1: username like "%"#{username}"%"
配置文件2: username like "%${value}%"
如果传的是简单类型必须使用value
如果是pojo,属性名引用
d、参数
简单类型: 基本数据类型,String
如果${} 必须用value引用
如果#{} 随便写
pojo类型:属性名引用
e、${} 与 #{}区别
${}:直接拼接,不会转换类型, 不能防注入
#{}:转换类型后拼接, 相当于占位符?,可以防注入
h、转换类型
入参:pojo
<update id="update" parameterType="com.itheima.domain.User">
UPDATE user set username = ${username},password = #{password},
where id = #{id}
</update>
a、 ${username}传入的是 李四 #{username}传入的是 "李四"
b、当数据库类型是datetime类型时,#{birth}传入String类型依然能够成功转换。
因此,使用${}应手动转换类型 username = "${username}"
所以,#{}优势更大。
传统Dao开发
Dao接口
public interface UserDao { //接口方法
public List<User> findAll();
public void save(User user);
public void update(User user);
public void del(Integer id);
}
DaoImpl实现类
public class UserDaoImpl implements UserDao {
//所有的方法共用的factory对象,应该是属于应用级别
private SqlSessionFactory sessionFactory;
public UserDaoImpl(SqlSessionFactory sessionFactory) {
//构造方法,必须传入参数sessionFactory,才能创建此类对象
this.sessionFactory = sessionFactory;
}
@Override
public List<User> findAll() {
//每一个方法应该获取一个SqlSession对象,用完应该立即关闭,因为线程不安全
SqlSession sqlSession = sessionFactory.openSession();
List<User> userList = sqlSession.selectList("userMapper.findAll");
sqlSession.close();
return userList;
}
测试程序
public class TestMybatisDao {
SqlSessionFactory sqlSessionFactory = null;
@Before
public void init(){
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindAll(){
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
}
原始方式开发Dao层时,如果接口中定义了很多方法,
那么实现类中就得写很多的实现代码,但Dao层的逻辑总结起来就是增、删、改、查,
是否可以不写实现类?
动态代理模式
动态代理模式只需要Dao接口,不需要实现类
xxxMapper.xml必须遵守
namespace:必须是对应接口的全限类名(…dao.UserDao)
select|update|insert|delete: 四个标签 id必须对应dao接口的方法名
入参和返回类型也要相同
Dao接口
和上述一致
Mapper.xml
<mapper namespace="com.mybatis.dao.UserDao">
<select id="findAll" resultType="com.mybatis.domain.User">
select * from user
</select>
</mapper>
测试程序
@Test
public void testFindAll(){
SqlSession sqlSession = sessionFactory.openSession();
//获取Dao接口的动态代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
全局配置文件 SqlMapConfig.xml
配置文件中的标签和顺序:
properties?, 配置属性(重要)
settings?,
typeAliases?, 类型别名(重要)
typeHandlers?, 类型转换(操作)(了解)
objectFactory?, objectWrapperFactory?, reflectorFactory?,
plugins?,
environments?,
databaseIdProvider?,
mappers? 引入映射配置文件(重要)
? : 一个或者零个
| : 任选其一
+ : 最少一个
* : 零个或多个
, : 必须按照此顺序编写
properties
<?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>
<!--属性配置-->
<!--<properties>-->
<!--<property name="jdbc.driver" value="com.mysql.jdbc.Driver"></property>-->
<!--<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatisdb_331"></property>-->
<!--<property name="jdbc.username" value="root"></property>-->
<!--<property name="jdbc.password" value="root"></property>-->
<!--</properties>-->
<!--引入外部属性文件-->
<properties resource="jdbc.properties"></properties>
<!--
${jdbc.driver}:ognl表达式
在xml中没有el表达式
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
typeAliases
<!--类型别名映射-->
<typeAliases>
<!--单个类型映射-->
<!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
<!--包的映射:引入该包中所有的pojo类型,配置别名: 简单类名(不区分大小写)-->
<package name="com.itheima.domain"></package>
</typeAliases>
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{abc}
</select>
mappers
<mappers>
<!-- 四种参数分别对应不同的方法-->
<mapper url="" resource="" class=""></mapper>
<package name="" ></package>
</mappers>
<mappers>
<!--引入UserMapper.xml配置文件 resource:直接引入-->
<!--<dao resource="com/itheima/dao/UserDao.xml"/>-->
<!--引入UserMapper的配置文件:url:绝对路径-->
<!--<mapper url="file:///F:\ideaworkspace\project\mybatis_day02_4_config\src\main\resources\com\itheima\dao\UserDao.xml"></mapper>-->
<!--引入UserDao接口
通过接口引入配置:class:
前提:必须在同一个包中
文件名称必须一致 -->
<!--<mapper class="com.itheima.dao.UserDao"></mapper>-->
<!--通过接口引入配置:package name:
前提:必须在同一个包中
文件名称必须一致 -->
<!--引用一个包中的所有dao接口-->
<package name="com.itheima.dao"></package>
</mappers>
后面两种方式仅支持动态代理开发
推荐使用<package/>批量加载的方式,这种方式也用的最多。
输入参数类型和输出参数类型
1. 输入参数
简单类型: 基本数据类型+ String类型
#{} :名称随便
${} :${value}
pojo 类型
#{} :${} : 属性名引用
包装对象类型(QueryVo):需要传入多个参数
引用 #{属性.属性名}
Map集合
引用: #{key}
多个参数
引用时:#{param1},#{param2}.....#{paramN}
2. 返回值类型
如果列与属性名不一致,对应的属性为null, 必须写映射配置
包装对象类型(QueryVo):需要传入多个参数
<select resultType="user" parameterType="queryvo" id="findByQueryVO">
select * from user where username like "%"#{user.username}"%"
limit #{startIndex},#{pageSize}
</select>
queryvo中包装了User对象、startIndex、pageSize
Map集合
<select resultType="user" parameterType="map" id="findByMap">
select * from user where username like "%"#{username}"%"
limit #{startIndex},#{pageSize}
</select>
// 创建map对象
Map<String,Object> map = new HashMap<>();
map.put("username","小");
map.put("startIndex",0);
map.put("pageSize",2);
map中以键值对存储数据
引用: #{key}
多个参数
<select resultType="user" id="findByManyParam">
select * from user where username like "%"#{param1}"%"
limit #{param2},#{param3}
</select>
//依次传入参数
List<User> userList = userDao.findByManyParam("小", 0 ,2);
返回值类型
<mapper namespace="com.itheima.dao.UserDao">
<!--resultMap:结果映射:一般用户列名与属性名不一致的情况-->
<!--id="":唯一的标识 type="":返回值的类型 -->
<resultMap type="user" id="userList">
<!--id:一般写主键的映射 property: 属性名 column: 列名 -->
<id column="uid" property="id"/>
<!--映射其他属性和列-->
<result column="uname" property="username"/>
</resultMap>
<select id="findAll" resultMap="userList">select * from user </select>
</mapper>