增删改查
id:对应的namespace中的方法名。
resultType:Sql语句执行返回值。
parameterType:参数类型。
增删改提交事务。 sqlSession.commit();
增
insert:
编写接口:
int insertUser(User user);
编写sql语句:
<insert id="insertUser" parameterType="com.pojo.User" >
insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>
测试:
@Test
public void insertUser(){
//第一步获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.insertUser(new User(6,"77","222222"));
if (res>0){
System.out.println("insert success");
}
sqlSession.commit();
sqlSession.close();
}
删
delete
编写接口:
int deleteUser(int id);
编写sql语句:
<delete id="deleteUser" parameterType="com.pojo.User">
delete from mybatis.user where id = #{id};
</delete>
测试:
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
改
update
编写接口:
int updateUser(User user);
编写sql语句:
<update id="updateUser" parameterType="com.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id};
</update>
测试:
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(5,"66","333333"));
sqlSession.commit();
sqlSession.close();
}
模糊查询
首先在UserMapper接口中声明方法:
List<User> getUserLike(String value);
然后在UserMapper.xml中写sql语句:
<select id="getUserLike" resultType="com.pojo.User">
select * from mybatis.user where name like #{value};
</select>
测试:
java代码执行的时候,传递通配符% %
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("%li%");
for (User user : userList) {
System.out.println(user);
}
sqlSession.commit();
sqlSession.close();
}
配置解析
1.核心配置
1.1 mybatis-config.xml;
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
2.环境变量(environments)
MyBatis 可以配置成适应多种环境,不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:
- 每个数据库对应一个 SqlSessionFactory 实例****
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
-
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-
MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
数据源(dataSource)
type="[UNPOOLED|POOLED|JNDI]
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。这种数据源配置只需要两个属性:
重点理解pooled。
3.属性(properties)
我们可以通过properties属性来实现引用这些配置文件。
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。[db.properties]
编写一个配置文件
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT
username = root
password = 123456
在核心配置文件中引入
<!--引入外部配置文件-->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
<!--优先外部配置文件-->
</properties>
可以直接引入外部配置文件
可以在引入步骤中增加一些配置文件
如果上述中有重复,优先外部配置文件中的东西。
4.类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。可以有效的减少冗余。
<typeAliases>
<typeAlias type="com.pojo.User" alias="user"/>
</typeAliases>
上述代码将“com.pojo.user”起了别名“user”。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="com.pojo"/>
</typeAliases>
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。
扫描实体类的包,它的默认别名就是这个类的类名,首字母小写。
在实体类较少时使用第一种方式,实体类较多时使用第二种方式。
第一种可以DIY别名,第二种则不行。如果非要改,则在实体类上增加注解。
@Alias("hello")
public class User {
}
5.设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
数据库字段用下划线,例如:last_name,如果写成lastname,数据库会自动变为LASTNAME。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ugBqPufp-1625058727069)(C:\Users\ZYH.LAPTOP-32L7159T\AppData\Roaming\Typora\typora-user-images\image-20210630105932303.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jVo5Qn9r-1625058727073)(C:\Users\ZYH.LAPTOP-32L7159T\AppData\Roaming\Typora\typora-user-images\image-20210630110007005.png)]
目前需要知道的设置的东西。
6. 映射器(mappers)
MapperRegistry:注册绑定我们的Mapper文件;
记住命名规范:
接口与他的Mapper配置文件必须同名;例如(UserMapper接口和UserMapper.xml文件的命名)
接口和他的Mapper配置文件必须在同一个包下。
方式一:直接使用资源路径文件**【推荐使用】**
<mappers>
<mapper class="com/dao/UserMapper.xml"/>
</mappers>
方式二:使用class
<mappers>
<mapper class="com.dao.UserMapper"/>
</mappers>
方式三:扫描包注入绑定
<mappers>
<package name = "com.pojo"/>
</mappers>
7. 生命周期和作用域
生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题
SqlSessionFactoryBuilder
一旦创建了SqlSessionFactory,就不再需要它了
局部变量
SqlSessionFactory
说白了可以看成数据库连接池
一旦创建了就一致存在,没有任何理由丢弃它或者重新创建另一个实例。
最简单的就是使用单例模式或者静态单例模式。
SqlSession
连接到连接池的一个请求
SqlSession的实例不是线程安全的,因此不能被共享的,所以它的最佳作用域是请求或方法作用域。
用完之后赶紧关闭,否则资源被占用。
解决属性名和字段名不一致的问题ResultMap
public class User {
private int id;
private String name;
private String password;
}
上述中的password与数据库中的pwd不一致,注意:我们在定义时应当与数据库中参数类型名称一致,能够避免很多多余的操作
解决方法
-
起别名
<select id="getByID" resultType="com.pojo.User" parameterType="int"> select id,name,pwd as password from mybatis.user where id = #{id} </select>
-
resultMap
结果集映射
id name pwd id name password
<resultMap id = "UserMap" type="User"> <result column="pwd" property="password"/> </resultMap> <select id = "getByID" resultMap="UserMap"> select * from mybatis.user where id = #{id} </select>
哪个不用映射哪个就行。
日志
如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!
曾经:sout、debug
现在:日志工厂
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1YSdYzy-1625058727076)(C:\Users\ZYH.LAPTOP-32L7159T\AppData\Roaming\Typora\typora-user-images\image-20210630105932303.png)]
SLF4J
LOG4J 【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING 【掌握】
NO_LOGGING
具体使用哪一个日志实现,在设置中设定!
STDOUT_LOGGING 【掌握】
在mybatis核心配置文件中即mybatis-config.xml中配置了STDOUT_LOGGING。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
输出为:
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 775931202.
==> Preparing: select * from mybatis.user;
==> Parameters:
<== Columns: id, name, pwd
<== Row: 1, zhangsan, 123456
<== Row: 2, lisi, 123456
<== Row: 3, wangwu, 123456
<== Row: 5, 66, 333333
<== Row: 6, 77, 222222
<== Row: 8, liwu, 444444
<== Row: 9, ss, 555555
<== Total: 7
User{id=1, name='zhangsan', pwd='123456'}
User{id=2, name='lisi', pwd='123456'}
User{id=3, name='wangwu', pwd='123456'}
User{id=5, name='66', pwd='333333'}
User{id=6, name='77', pwd='222222'}
User{id=8, name='liwu', pwd='444444'}
User{id=9, name='ss', pwd='555555'}
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2e3fc542]
Returned connection 775931202 to pool.
LOG4J【掌握】
1.先导入包
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2.log4j.properties
# priority :debug<info<warn<error
#you cannot specify every priority with different file for log4j
log4j.rootLogger=debug,stdout,info,debug,warn,error
#console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
#info log
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.info.File=./log/info.log
log4j.appender.info.Append=true
log4j.appender.info.Threshold=INFO
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#debug log
log4j.logger.debug=debug
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.debug.File=./log/debug.log
log4j.appender.debug.Append=true
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#warn log
log4j.logger.warn=warn
log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
log4j.appender.warn.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.warn.File=./log/warn.log
log4j.appender.warn.Append=true
log4j.appender.warn.Threshold=WARN
log4j.appender.warn.layout=org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#error
log4j.logger.error=error
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.error.File = ./log/error.log
log4j.appender.error.Append = true
log4j.appender.error.Threshold = ERROR
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
3.在mybatis-config.xml中配置设置
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4.log4j的使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dy0mdYvs-1625058727081)(C:\Users\ZYH.LAPTOP-32L7159T\AppData\Roaming\Typora\typora-user-images\image-20210630151235731.png)]
简单使用
1.在使用Log4j的类中,导入包import org.apache.log4j.Logger;
2.日志对象,参数为当前类的class,
static Logger logger = Logger.getLogger(UserMapperTest.class);
3.日志级别
public void testLog4j(){
logger.info("info:enter testLog4j");
logger.debug("debug:enter testLog4j");
logger.error("error:enter testLog4j");
logger.warn("warn:enter testLog4j");
}
分页
Limit
减少数据的处理量
select * from user limit startIndex,pageSize
startIndex是指起始数据下标从0开始,pageSize指查几个。
select * from user limit 0,3
输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwb98PJS-1625058727086)(C:\Users\ZYH.LAPTOP-32L7159T\AppData\Roaming\Typora\typora-user-images\image-20210630152746633.png)]
select * from user limit 3 #[0,3]
使用Mybatis实现分页,核心SQL
1.接口
List<User> getUserByLimit(Map<String,Integer> map);
2.Mapper.xml
<select id="getUserByLimit" resultType="com.pojo.User" parameterType="map">
select * from mybatis.user limit #{startIndex},#{pageSize};
</select>
3.测试
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
RowBounds分页(了解即可)
知道有这个分页方法即可。
使用注解开发
测试
1.接口中定义方法
@Select("select * from user")
List<User> getUserList();
2.mybatis-config.xml中进行配置
<mappers>
<mapper class="com.dao.UserMapper"></mapper>
</mappers>
3.测试
@Test //查询全部
public void getAllUser(){
//第一步获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用接口中的的方法
List<User> userList = mapper.getUserList();
//输出
for (User user : userList) {
System.out.println(user);
}
//关闭
sqlSession.close();
}
CRUD
我们可以在工具类创建时实现自动提交事务。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);}
设置为true。
增删
@Select("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
int insertUser(User user);
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id") int id);
}
测试
@Test
public void insertUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用接口中的的方法
mapper.insertUser(new User(5, "zyh", "123456"));
sqlSession.close();
}
@Test
public void deleteUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//获取接口对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用接口中的的方法
mapper.deleteUser(5);
sqlSession.close();
}
Param()注解
基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型的话,可以忽略,建议加上
#{} 和 ${}的区别要清楚
多对一处理
例如:多个学生对应一个老师
对于学生,是关联,多个学生关联一个老师
对于老师,是集合,一个老师含有一个学生集合。
项目模块为mybatis-04
<mapper namespace="com.dao.StudentMapper">
<select id="getStudent" resultMap="StudentTeacher">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
</mapper>
多对一主要使用association。
一对多处理
项目为mybatis-05
接口方法
//获取指定老师下的学生及老师信息
Teacher getTeacher2(@Param("tid") int id);
xml中sql语句
<select id="getTeacher2" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>
测试语句
@Test
public void getTeacher2Test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher2(1);
System.out.println(teacher);
sqlSession.close();
}