centos特有软件-邮件服务-sendmail(linux默认邮件服务器)

Linux服务器mail程序本身就是调用sendmail来进行邮件发送的,sendmail服务器提供对外的邮件发送功能。CentOS默认不能发送邮件,需要发送邮件的童鞋可以安装一个sendmail程序。

一、搭建sendmail

[root@ProxyServer ~]# yum -y install sendmail
[root@ProxyServer ~]# /etc/init.d/sendmail start
Starting sendmail:                                         [  OK  ]
Starting sm-client:                                        [  OK  ]
[root@ProxyServer ~]# chkconfig sendmail on
[root@ProxyServer ~]# man mail
......
       mailx [-BDdEFintv~] [-s subject] [-a attachment ] [-c cc-addr] [-b bcc-addr] [-r from-addr] [-h hops] [-A account]
              [-S variable[=value]] to-addr . . .
       mailx [-BDdeEHiInNRv~] [-T name] [-A account] [-S variable[=value]] -f [name]
       mailx [-BDdeEinNRv~] [-A account] [-S variable[=value]] [-u user]
......

centos7  是   systemctl  start  sendmail  不用 /etc/init.d/sendmail start
centos7   不需要  chkconfig sendmail on 这是开机启动的意思
man mail 是查看帮助文档的意思

我自己电脑测试了一下:发现 mail命令和mailx命令,都是安装了mailx才有的。所以还应该安装 yum install mailx

1、通过命令行发送邮件

cooldeMacBook-Pro:~ cool$ mail -s "这里写邮件标题" [email protected] 
这里写邮件正文
信息 
随便写
EOT
cooldeMacBook-Pro:~ cool$

第一行是输入的命令,-s表示邮件的主题,后面的[email protected]则是邮件的接收人,输入完这行命令后回车,会进入邮件正文的编写,可以输入任何文字,比如上面的三行。当邮件正文输入完成后,需要按CTRL+D结束输入。

这样本地电脑可以发送成功到指定邮箱。目标收件箱显示:邮件来自:
“cool@cooldeMacBook-Pro.local

经过测试:-s 后面的 邮件主题 可以不加 双引号,也没有问题,结果和原来一样,寄件人显示 "cool
mail -s test [email protected]

【寄件人”cool 是电脑用户名,寄件地址 cooldeMacBook-Pro.local 是主机的hostname】

cooldeMacBook-Pro:~ cool$ echo $HOSTNAME
cooldeMacBook-Pro.local

同理,centos 上操作和mac系统中一样。

因为线上服务器中我设置的hostname 是cool 【不是xxx.yyy类型】所以163邮箱服务器拒收了,系统退信。原因是邮件地址名 不规范。但是之前没有找到原因,所以在sendmail基础上索性就配置smtp 服务,用来代发送邮件。

2、使用管道进行邮件发送

cooldeMacBook-Pro:~ cool$ echo "hello,echo pip"|mail -s "subject pip" [email protected]

使用管道直接敲入这行命令即可完成邮件的发送,其中echo后的是邮件正文。

3、使用文件进行邮件发送

bikedeMacBook-Pro:~ cool$ mail -s "用文件来填写正文" [email protected] </Users/bike/Desktop/testfile.txt

4、邮件发送附件

很多情况下,我们也需要使用邮件来发送附件,在linux下使用mail命令发送附件也很简单,不过首先需要安装uuencode软件包,这个程序是对二进制文件进行编码使其适合通过邮件进行发送,直接使用centos的yum源可能找不到uuencode命令的包sharutils,我这里使用了网易Yum源。

[root@ProxyServer yum.repos.d]# yum -y install sharutils
[root@ProxyServer yum.repos.d]# uuencode CentOS6-Base-163.repo 163_yum_repo |mail -s "附件" [email protected] < /etc/passwd
[root@ProxyServer yum.repos.d]#

CentOS6-Base-163.repo 文件作为邮件的附件发送出去了。uuencode有两个参数,第一个是要发送的文件CentOS6-Base-163.repo,第二个是显示的文件名称163_yum_repo。

二、发送失败和查看邮件退信

如果提示mail: command not found

[root@ProxyServer ~]# mail -s "password" [email protected] < /etc/passwd
-bash: mail: command not found

那么就是没有安装mail命令,此时需要安装mail命令

[root@ProxyServer ~]# yum install mailx -y
[root@ProxyServer ~]# rpm -qa|grep mail
libreport-plugin-mailx-2.0.9-19.el6.x86_64
mailx-12.4-7.el6.x86_64
procmail-3.22-25.1.el6.x86_64
mailcap-2.1.31-2.el6.noarch
sendmail-8.14.4-8.el6.x86_64
[root@ProxyServer ~]#

总结来说:mailx 是 sendmail 和 Postfix mail 的基础,mail 命令 和 mailx 命令都依赖于 mailx。

输入 mail 或 mailx 命令,可以查看   /var/spool/mail/用户名文件夹(比如root)    下的所有的邮件。【注意安装sendmail软件时,不会再用户根目录下生成一个mbox文件夹mail -f mbox 命令 用来 显示当前终端 目录下mbox文件夹中的邮件。mail -f 命令默认缺省路径是:(用户根目录比如/Users/cool)/mbox  。所以只安装了sendmail软件的执行 mail -f 命令,会发现找不到目标文件夹。

mac系统下用的是Postfix mail【也就是说安装时会生成一个用户根目录下的mbox文件夹】,mail -f mbox 命令 用来 显示当前终端 目录下mbox文件夹中的邮件。mail -f 命令默认缺省路径是:(用户根目录比如/Users/cool)/mbox  但是奇怪的是 mac下mail 命令显示没有邮件,但是 /Users/cool/mbox 下有邮件。

输入 数字+回车,选择邮件列表中的某个邮件。
输入 空格,翻页查看邮件内容
输入 q +回车 退出邮箱

邮件的查看
mail          //出现& 在后台输入命令
Enter键   //查看当前邮件
+    //下一封邮件     —   //上一封邮件
d 数字  //删除它几号信件
s 文件名  //将信件保存为文件
r //回信  q  //退出

看下文,邮件退信的原因是:550 MI:IMF

•550 MI:IMF 发信人电子邮件地址不合规范。
请参考http://www.rfc-editor.org/关于电子邮件规范的定义;
参考帮助网站:
http://help.163.com/09/1224/17/5RAJ4LMH00753VB8.html

退信全文:

[root@superguy ~]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/root": 12 messages 3 unread
    1 Mail Delivery Subsys  Sat Sep 29 07:27  73/2143  "Returned mail: see tr"
    2 Mail Delivery Subsys  Sat Sep 29 07:27  76/2692  "Returned mail: see tr"
    3 Mail Delivery Subsys  Sat Sep 29 07:27  76/2693  "Returned mail: see tr"
    4 Mail Delivery Subsys  Sat Sep 29 07:27  72/2537  "Returned mail: see tr"
    5 Mail Delivery Subsys  Sat Sep 29 07:27  71/2637  "Returned mail: see tr"
    6 Mail Delivery Subsys  Sat Sep 29 07:27  71/2637  "Returned mail: see tr"
>U  7 Mail Delivery Subsys  Sat Sep 29 07:27  70/2554  "Returned mail: see tr"
 U  8 Mail Delivery Subsys  Sat Sep 29 07:27  71/2636  "Returned mail: see tr"
 U  9 Mail Delivery Subsys  Sat Sep 29 07:27  71/2636  "Returned mail: see tr"
   10 Mail Delivery Subsys  Sat Sep 29 07:28  72/2633  "Returned mail: see tr"
   11 Mail Delivery Subsys  Sat Sep 29 08:16 103/4273  "Returned mail: see tr"
   12 Mail Delivery Subsys  Sat Sep 29 14:01 103/4259  "Returned mail: see tr"
& 7
Message  7:
From MAILER-DAEMON@superguy  Sat Sep 29 07:27:45 2018
Return-Path: <MAILER-DAEMON@superguy>
Date: Sat, 29 Sep 2018 07:27:45 GMT
From: Mail Delivery Subsystem <MAILER-DAEMON@superguy>
To: <root@superguy>
Content-Type: multipart/report; report-type=delivery-status;
	boundary="w8T7Rjim011448.1538206065/superguy"
Subject: Returned mail: see transcript for details
Auto-Submitted: auto-generated (failure)
Status: RO

Part 1:

The original message was received at Sat, 29 Sep 2018 07:27:40 GMT
from localhost [127.0.0.1]

   ----- The following addresses had permanent fatal errors -----
<[email protected]>
    (reason: 550 MI:IMF 163 mx14,QMCowAB3utduKa9bdw4FGw--.17130S3 1538206064 htt
p://mail.163.com/help/help_spam_16.htm?ip=118.118.118.118&hostid=mx14&time=153820
6064)

   ----- Transcript of session follows -----
... while talking to 163mx01.mxmail.netease.com.:
>>> MAIL From:<root@superguy> SIZE=617
<<< 550 MI:IMF 163 mx14,QMCowAB3utduKa9bdw4FGw--.17130S3 1538206064 http://mail.
163.com/help/help_spam_16.htm?ip=118.118.118.118&hostid=mx14&time=1538206064
554 5.0.0 Service unavailable

Part 2:
Content-Type: message/delivery-status


Part 3:
Content-Type: message/rfc822

From root@superguy Sat Sep 29 07:27:40 2018
Return-Path: <root@superguy>
From: root <root@superguy>
Date: Sat, 29 Sep 2018 07:22:57 +0000
To: [email protected]
Subject: test
User-Agent: Heirloom mailx 12.5 7/5/10
Content-Type: text/plain; charset=us-ascii

hello test
&

解决163邮箱退信办法,修改hostname,因为邮件地址是根据hostname来的,hostname应该改为 xxx.yyy

三、smtp邮件配置

其实这里用到的是mailx软件,mailx软件是在安装sendmail软件时,有可能已经自动下载了,有可能还没下载。

bin/mail会默认使用本地sendmail发送邮件,这样要求本地的机器必须安装和启动Sendmail服务,而通过修改配置文件/etc/mail.rc(/etc/nail.rc)可以使用外部SMTP服务器,可以达到不使用sendmail而用外部的smtp服务器发送邮件的目的。

不用管posix mail 和 sendmail ,只要配置好smtp后,就可以直接用mail 命令行发邮件了。发件人就是下面配置好的user。

[root@ProxyServer ~]# vim /etc/mail.rc          #文末添加以下
 set [email protected] 
 set smtp=smtp.51cto.com
 set [email protected] 
 set smtp-auth-password=51cto 
 set smtp-auth=login
[root@ProxyServer ~]# source /etc/mail.rc
[root@ProxyServer ~]# mail -s "51cto" 15001*****@139.com < /etc/passwd

from:发送的邮件地址(真实地址,我测试时候直接写justin发送邮件失败),对方显示的发件人
smtp:发生的外部smtp服务器的地址
smtp-auth-user:外部smtp服务器认证的用户名
smtp-auth-password:外部smtp服务器认证的用户密码(我测试过用邮箱登录密码OK)
smtp-auth:邮件认证的方式

四、邮箱命令行介绍

-b<地址>:指定密件副本的收信人地址;
-c<地址>:指定副本的收信人地址;
-f<邮件文件>:读取指定邮件文件中的邮件;
-i:不显示终端发出的信息;
-I:使用互动模式;
-n:程序使用时,不使用mail.rc文件中的设置;
-N:阅读邮件时,不显示邮件的标题;
-s<邮件主题>:指定邮件的主题;
-u<用户帐号>:读取指定用户的邮件;
-v:执行时,显示详细的信息。

1、使用sendmail -bp 或者 mailq 可以查看到邮件发送队列,里边会列出有几个邮件等待发送。

mailq 查看队列Postfix mail 会报错因为服务没有开启,需要 sudo postfix status ,sudo postfix start 

[root@CHINFO3 mqueue]# mailq
		/var/spool/mqueue (5 requests)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
tB36BqUi005128     1716 Thu Dec  3 14:11 <infa@chinfo3>
                 (Deferred: mx.263.net.: No route to host)
					 <[email protected]>
tB21TicN013397      415 Wed Dec  2 09:29 <infa@chinfo3>
                 (Deferred: mx.263.net.: No route to host)
					 <[email protected]>
......
[root@CHINFO3 mqueue]# sendmail -bp
		/var/spool/mqueue (5 requests)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
tB36BqUi005128*    1716 Thu Dec  3 14:11 <infa@chinfo3>
                 (Deferred: mx.263.net.: No route to host)
					 <[email protected]>
tB21TicN013397      415 Wed Dec  2 09:29 <infa@chinfo3>
                 (Deferred: mx.263.net.: No route to host)
					 <[email protected]>
......
[root@CHINFO3 mqueue]#

邮件队列的文件都保存在 /var/spool/mqueue/ 文件夹内,查看此文件夹时,可以看到邮件队列内的邮件:【命令行 pwd  是输出当前目录】

[root@CHINFO3 mqueue]# pwd
/var/spool/mqueue
[root@CHINFO3 mqueue]# ls
dftB111d4Q031164  dftB213omV012806  dftB36BqUi005128  qftB117J4b006323  qftB21TicN013397
dftB117J4b006323  dftB21TicN013397  qftB111d4Q031164  qftB213omV012806  qftB36BqUi005128
[root@CHINFO3 mqueue]#

如果需要删除队列,直接清空该文件夹即可:【当前在这个 /var/spool/mqueue目录】

[root@CHINFO3 mqueue]# pwd
/var/spool/mqueue
[root@CHINFO3 mqueue]# ls
dftB111d4Q031164  dftB213omV012806  dftB36BqUi005128  qftB117J4b006323  qftB21TicN013397
dftB117J4b006323  dftB21TicN013397  qftB111d4Q031164  qftB213omV012806  qftB36BqUi005128
[root@CHINFO3 mqueue]# rm -f *
[root@CHINFO3 mqueue]# ls
[root@CHINFO3 mqueue]# mailq
/var/spool/mqueue is empty
		Total requests: 0
[root@CHINFO3 mqueue]#

2、tail  /var/log/maillog   查看日志 或者如下 

[root@CHINFO3 ~]# cd /var/log/
[root@CHINFO3 log]# cat mail
mail/      maillog    maillog.1  maillog.2  maillog.3  maillog.4  
[root@CHINFO3 log]# cat mail

五、SendMail服务启动慢总结

在 CentOS release 6.6 上启动sendmail服务时发现服务启动过程非常慢,基本上要耗费3分多钟。有点纳闷:什么原因导致sendmail启动这么慢?搜索了这方面的一些资料,结合自己的理解,把它梳理一遍。权当笔记。

[root@MySQL-T01 bin]# service sendmail stop
Shutting down sm-client: [ OK ]
Shutting down sendmail: [ OK ]
[root@MySQL-T01 bin]# date 
Wed Aug 5 09:11:00 UTC 2015
[root@MySQL-T01 bin]# service sendmail start
Starting sendmail: [ OK ]
Starting sm-client: [ OK ]
[root@MySQL-T01 bin]# date
Wed Aug 5 09:14:53 UTC 2015

如上所示,sendmail服务的启动整整需要花费3分多钟。因为Starting sendmail、Starting sm-client这两步check需要查询你设置的主机名的A记录或反向域名记录,由于全球9台DNS根系统都在美国,这个时候会去查询本机主机名对应的dns A记录。查询可能会非常的慢.

通常的域名解析是指A记录解析,即主机记录解析,就是指把域名解析到虚拟主机的过程;又称IP指向,用户可以在此设置子域名并指向到自己的目标主机地址上,从而实现通过域名找到服务器。

让sendmial绕过查询远程主机,这里给出一种最简单的方法,给主机设置一个别名。

/etc/hosts原始配置

[root@MySQL-T01 bin]# more /etc/hosts
10.20.251.45 MySQL-T01 localhost
127.0.0.1   localhost  localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost  localhost.localdomain localhost6 localhost6.localdomain6

/etc/hosts修改配置

[root@MySQL-T01 bin]# vi /etc/hosts
10.20.251.45 MySQL-T01 localhost
127.0.0.1   localhost localhost.localdomain MySQL-T01
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

修改完成后,关闭sendmail服务,启动sendmail服务非常快,只要一两秒的样子。

[root@MySQL-T01 bin]# service sendmail stop
Shutting down sm-client: [  OK  ]
Shutting down sendmail: [  OK  ]
[root@MySQL-T01 bin]# service sendmail start
Starting sendmail: [  OK  ]
Starting sm-client: [  OK  ]
[root@MySQL-T01 bin]#

六、使用mailx465端口发送邮件

前面提到的邮件发送都是 25端口 发送的,在一些云服务器中为了防止邮件滥发,往往都对25端口做了限制,所以此时就使用到加密的465端口了,本篇文章以qq邮箱为例来配置mailx,通过465端口发送邮件。

1、关闭其它的邮件工具

下面是两种邮件服务器:

service sendmail stop
chkconfig sendmail off
service postfix stop
chkconfig postfix off

2、安装mailx

现在安装sendmail已经自动安装mailx了。

yum install mailx

3、在邮箱网站中开启smtp功能

开启后会得到一个授权码,这个授权码可以代替邮箱密码(自行去邮箱开启),如果用邮箱密码也没有问题。

4、请求数字证书

(这里用的163邮箱,所以向163请求证书)

mkdir -p /root/.certs/
echo -n | openssl s_client -connect smtp.163.com:465 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/.certs/163.crt
certutil -A -n "GeoTrust SSL CA" -t "C,," -d ~/.certs -i ~/.certs/163.crt
certutil -A -n "GeoTrust Global CA" -t "C,," -d ~/.certs -i ~/.certs/163.crt
certutil -A -n "GeoTrust SSL CA - G3" -t "Pu,Pu,Pu" -d ~/.certs/ -i ~/.certs/163.crt
certutil -L -d /root/.certs

最后会在 /root/.certs/   文件夹下面:生成4个文件:

### 我用163服务器 做测试通过了,证书文件夹下面有如下4个 文件  
163.crt  cert8.db   key3.db secmod.db

5、配置/etc/mail.rc

set [email protected] #之前设置好的邮箱地址
set smtp=smtps://smtp.163.com:465 #邮件服务器
set [email protected] #之前设置好的邮箱地址
set smtp-auth-password=xxxx #授权码
set smtp-auth=login #默认login即可
set ssl-verify=ignore #ssl认证方式
set nss-config-dir=/root/.certs #证书所在目录

smtp-auth-password:外部smtp服务器认证的用户密码(我测试过用邮箱登录密码也OK)【在前面提到的第三步在网站邮箱中开启smtp,就可以获取授权码】

6、重新加载配置

source /etc/mail.rc

7、发送邮件测试

echo "邮件正文" | mail -s "邮件主题" [email protected]

七、删除mail邮件

方法一:使用mail命令,然后在 & 提示符下使用 d 命令(Delete),批量删除邮件,例如删除1~53邮件:

  # mail
  & d 1-53

方法二:删除全部系统邮件

  # > /var/spool/mail/root    or  cat /dev/null > /var/spool/mail/root

  或者

  # echo "d *" |mail -N

参考:

http://blog.51cto.com/ityunwei2017/1713425
https://www.cnblogs.com/kerrycode/p/4717498.html

Centos使用mailx465端口发送邮件

补充:MUA、MDA、MTA
http://blog.51cto.com/20101218/701794
https://www.cnblogs.com/horizonli/p/5591438.html

bash-运算-脚本中获取到命令执行结果值

#!/bin/bash

# 反引号 就是将运行的 命令行结果 赋值给 result 
 result=`mysqladmin -u root -pKitty521! ping`

# result=`/usr/bin/mysqladmin ping`

# 单引号 ,双引号 都可以 保存 普通 字符串 变量
expected='mysqld is alive'

if [[ "$result" = "$expected" ]]

then

echo "mysqld is alive"

else

echo "It's dead - restart mysql"

fi

bash中:单引号与双引号的区别

单引号中是原始字符串
双引号可以对特殊字符进行扩展,如
a=bcdef
echo “$a” #双引号将进行变量扩展 ,输出bcdef
echo ‘$a’ #单引号直接输出$a

bash-文件-linux命令行输出重定向

无论是shell 还是 dos ,用法是一样的。

一共有4个输出到文件的命令,现以jar命令打war包举例说明:

命令 说明 举例
> 正常输出覆盖指定文件  jar -xvf my.war @select.txt  > output.txt
2> 正常输出尾部追加到指定文件  jar -xvf my.war @select.txt  2> output.txt
>> 异常输出覆盖指定文件  jar -xvf my.war @select.txt  >> error.txt
2>> 异常输出尾部追加到指定文件  jar -xvf my.war @select.txt  2>> error.txt

 

# 我这里用到 的 重定向 测试
netstat -r >/Users/cool/Desktop/test.txt

 

bash-概述-bash和shell的区别

Linux 中的 shell 有很多类型,其中最常用的几种是: Bourne shell (sh)、C shell (csh) 和 Korn shell (ksh), 各有优缺点。Bourne shell 是 UNIX 最初使用的 shell,并且在每种 UNIX 上都可以使用, 在 shell 编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种shell。Linux 操作系统缺省的 shell 是Bourne Again shell,它是 Bourne shell 的扩展,简称 Bash,与 Bourne shell 完全向后兼容,并且在Bourne shell 的基础上增加、增强了很多特性。Bash放在/bin/bash中,它有许多特色,可以提供如命令补全、命令编辑和命令历史表等功能,它还包含了很多 C shell 和 Korn shell 中的优点,有灵活和强大的编程接口,同时又有很友好的用户界面。

GNU/Linux 操作系统中的 /bin/sh 本是 bash (Bourne-Again Shell) 的符号链接,但鉴于 bash 过于复杂,有人把 ash 从 NetBSD 移植到 Linux 并更名为 dash (Debian Almquist Shell),并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Dash Shell 比 Bash Shell 小的多,符合POSIX标准。

Ubuntu继承了Debian,所以从Ubuntu 6.10开始默认是Dash Shell。

luotaijia@ubuntu:~$ ls -l /bin/sh /bin/bash 
-rwxr-xr-x 1 root root 801808 2010-08-11 03:58 /bin/bash 
lrwxrwxrwx 1 root root 4 2012-11-28 08:06 /bin/sh -> dash

在centos中,
1、/bin 是超链接 指向 /usr/bin
2、/bin/sh 【真实路径/usr/bin/sh】  是超链接 指向  /bin/bash 【真实路径/usr/bin/bash】

[cool@localhost /]$ ls -l /bin/sh&nbsp; 
lrwxrwxrwx. 1 root root 4 Jun 26 03:58&nbsp;/bin/sh -> bash
[cool@localhost /]$ ls -l /bin/bash
-rwxr-xr-x. 1 root root 964544 Apr 11 08:06&nbsp;/bin/bash

应该说, /bin/sh 与 /bin/bash 虽然大体上没什么区别, 但仍存在不同的标准. 标记为 “#!/bin/sh” 的脚本不应使用任何 POSIX 没有规定的特性 (如 let 等命令, 但 “#!/bin/bash” 可以). Debian 曾经采用 /bin/bash 更改 /bin/dash,目的使用更少的磁盘空间、提供较少的功能、获取更快的速度。但是后来经过 shell 脚本测试存在运行问题。因为原先在 bash shell 下可以运行的 shell script (shell 脚本),在 /bin/sh 下还是会出现一些意想不到的问题,不是100%的兼用。

Linux中的shell有多种类型,其中最常用的几种是Bourne shell(sh)、C shell(csh)和Korn shell(ksh)。三种shell各有优缺点。
Bourne shell是UNIX最初使用的shell,并且在每种UNIX上都可以使用。Bourne shell在shell编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种shell。

Linux操作系统缺省的shell是Bourne Again shell,它是Bourne shell的扩展,简称Bash,与Bourne shell完全向后兼容,并且在Bourne shell的基础上增加、增强了很多特性。Bash放在/bin/bash中,它有许多特色,可以提供如命令补全、命令编辑和命令历史表等功能,它还包含了很多C shell和Korn shell中的优点,有灵活和强大的编程接口,同时又有很友好的用户界面。
GNU/Linux 操作系统中的 /bin/sh 是 bash(Bourne-Again Shell)的符号链接,
但鉴于 bash 过于复杂,有人把 ash 从 NetBSD 移植到 Linux 并更名为 dash(Debian Almquist Shell),并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Ubuntu 号称自从他们在 6.10 版里这样做了以后,系统启动速度有了明显的提升。Debian 计划在下一个发行版(代号 lenny)中也将 dash 作为默认的 /bin/sh。

 

 

mysql问题-命令行连接mysql密码无效

mysql -u root -p 解释

 

使用此命令首先确保你的mysql运行环境已经搭建好

这是客户端连接mysql服务器的指令,比较全的写法是下面两种

第一个是全拼,第二个是第一个的缩写

mysql –host=localhost –user=myname –password=password mydb

mysql -h localhost -u myname -ppassword mydb

一般在使用中,我们会省略-h参数,mysql会自动默认为本地连接

还有一点就是各个参数之间是否有空格的问题,-u后面可以有也可以省略空格,对于-p后面的参数我要单独说一下

这是我从mysql官方文档拷过来的内容

for password options, the password value is optional:

If you use a -p or --password option and specify the password value, there must be no space between -p or --password= and the password following it.

  If you use a -p or --password option but do not specify the password value, the client program prompts you to enter the password. The password is not displayed as you enter it. This is more secure than giving the password on the command line. Other users on your system may be able to see a password specified on the command line by executing a command such as ps auxw

具体就是:对于password选项,此选项是可选的

如果你明确指定了-p或者–password的值,那么-p或者–password和密码值之间是不能有空格的。

如果你使用了-p或者–password选项但是没有给出password值,客户端程序提示您输入密码。

For mysql, the first nonoption argument is taken as the name of the default database. If there is no such option, mysql does not select a default database.

对于MySQL,第一个非选项参数被当作默认数据库的名称。如果没有这样的选项,MySQL就不会选择默认数据库。

也就是说在命令行中,你的mysql密码和-p或者–password参数之间有空格,mysql会认为你输入的是登录mysql后自动选择的数据库,而不是你所期望的密码

当然命令行连接数据库还有其它参数,这里主要介绍几个经常使用的,其它请参考https://dev.mysql.com/doc/refman/5.5/en/connecting.html

来自:https://www.cnblogs.com/phproom/p/9549229.html

mybatis映射文件-(8)-resultMap关联查询之discriminator鉴别器

鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为。比如封装Employee:根据gender值
1、如果查出的是女生:就把部门信息查询出来,否则不查询;
2、如果是男生,把last_name这一列的值赋值给email;

1、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

2、编辑 javabean

Employee.java

package com.mybatis.bean;

public class Employee {
	private int id;
	private String lastName;
	private String email;
	private String gender;
	private Department department;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}

}

Department.java

package com.mybatis.bean;

import java.util.List;

public class Department {
	
	private Integer id;
	private String departmentName;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getDepartmentName() {
		return departmentName;
	}
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName
				+ "]";
	}
	
	

}

3、编辑接口文件

EmployeeMapper.java

package com.mybatis.mapper;

import com.mybatis.bean.Employee;

public interface EmployeeMapper {
		
	public Employee getEmpByIdStep(Integer id);

}

DepartmentMapper.java

package com.mybatis.mapper;

import com.mybatis.bean.Department;

public interface DepartmentMapper {
	
	public Department getDeptById(Integer id);

}

4、编辑sql映射文件

EmployeeMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapperPlus">

	<!--自定义某个javaBean的封装规则
	type:自定义规则的Java类型
	id:唯一id方便引用
	  -->
	  
	<!-- public Employee getEmpById(Integer id); -->
	<select id="getEmpByIdStep"  resultMap="MyEmpDis">
		select * from tbl_employee where id=#{id}
	</select>
	
	
	<!-- =======================鉴别器============================ -->
	<!-- <discriminator javaType=""></discriminator>
		鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
		封装Employee:
			如果查出的是女生:就把部门信息查询出来,否则不查询;
			如果是男生,把last_name这一列的值赋值给email;
	 -->
	 <resultMap type="com.mybatis.bean.Employee" id="MyEmpDis">
	 	<id column="id" property="id"/>
	 	<result column="last_name" property="lastName"/>
	 	<result column="email" property="email"/>
	 	<result column="gender" property="gender"/>
	 	<!--
	 		column:指定判定的列名
	 		javaType:列值对应的java类型 ,string 是 mybatis 对String类型 直接默认设置 的别名 -->
	 	<discriminator javaType="string" column="gender">
	 		<!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap-->
	 		<case value="0" resultType="com.mybatis.bean.Employee">
	 			<association property="department" 
			 		select="com.mybatis.mapper.DepartmentMapper.getDeptById"
			 		column="d_id">
		 		</association>
	 		</case>
	 		<!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
	 		<case value="1" resultType="com.mybatis.bean.Employee">
		 		<id column="id" property="id"/>
			 	<result column="last_name" property="lastName"/>
			 	<result column="last_name" property="email"/>
			 	<result column="gender" property="gender"/>
	 		</case>
	 	</discriminator>
	 </resultMap>
</mapper>

DepartmentMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.DepartmentMapper">
	
	<!--public Department getDeptById(Integer id);  -->
	<select id="getDeptById" resultType="com.mybatis.bean.Department">
		select id,dept_name departmentName from tbl_dept where id=#{id}
	</select>

</mapper>

5、编辑全局配置文件:

mybatis-config.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>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="Kitty521!" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 
	如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
	-->
	<mappers>
	    <!-- 新方法操作mybatis 需要 的配置文件 -->
		<mapper resource="EmployeeMapperPlus.xml"  />
		<mapper resource="DepartmentMapper.xml" />
	</mappers>
	
</configuration>

特别注意:分步查询需要 调用两句sql语句。因为这两句sql语句分布在两个不同的sql映射文件,所以两个sql映射文件都需要注册到 全局配置文件中。

 

mybatis映射文件-(7)-resultMap关联查询之非级联一对多分步查询

1、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

2、编辑 javabean

Employee.java

package com.mybatis.bean;

public class Employee {
	private int id;
	private String lastName;
	private String email;
	private String gender;
	private Department department;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}

}

Department.java

package com.mybatis.bean;

import java.util.List;

public class Department {
	
	private Integer id;
	private String departmentName;
	private List<Employee> employees;
	
	
	public List<Employee> getEmployees() {
		return employees;
	}
	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getDepartmentName() {
		return departmentName;
	}
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName
				+ "]";
	}
	
	

}

3、编辑接口文件

DepartmentMapper.java

package com.mybatis.mapper;

import com.mybatis.bean.Department;

public interface DepartmentMapper {
	
	//分步查询
	public Department getDeptByIdStep(Integer id);

}

EmployeeMapper.java

package com.mybatis.mapper;

import java.util.List;

import com.mybatis.bean.Employee;

public interface EmployeeMapperPlus {
	
	public List<Employee> getEmpsByDeptId(Integer deptId);

}

4、编辑sql映射文件

DepartmentMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.DepartmentMapper">
	
<!-- collection:分步查询 -->
	<resultMap type="com.mybatis.bean.Department" id="MyDeptStep">
		<id column="id" property="id"/>
		<id column="dept_name" property="departmentName"/>
		<collection property="employees" 
			select="com.mybatis.mapper.EmployeeMapperPlus.getEmpsByDeptId"
			column="id" fetchType="lazy"></collection>
	</resultMap>
	<!-- public Department getDeptByIdStep(Integer id); -->
	<select id="getDeptByIdStep" resultMap="MyDeptStep">
		select id,dept_name from tbl_dept where id=#{id}
	</select>

		<!-- 扩展:多列的值传递过去:
			将多列的值封装map传递;
			column="{key1=column1,key2=column2}"
		fetchType="lazy":表示使用延迟加载;
				- lazy:延迟
				- eager:立即
	 -->
	
</mapper>

EmployeeMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapperPlus">

	<!--自定义某个javaBean的封装规则
	type:自定义规则的Java类型
	id:唯一id方便引用
	  -->
	
	<!-- public List<Employee> getEmpsByDeptId(Integer deptId); -->
	<select id="getEmpsByDeptId" resultType="com.mybatis.bean.Employee">
		select * from tbl_employee where d_id=#{deptId}
	</select>

</mapper>

5、编辑全局配置文件:

mybatis-config.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>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="Kitty521!" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 
	如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
	-->
	<mappers>
	    <!-- 新方法操作mybatis 需要 的配置文件 -->
		<mapper resource="EmployeeMapperPlus.xml"  />
		<mapper resource="DepartmentMapper.xml" />
	</mappers>
	
</configuration>

特别注意:分步查询需要 调用两句sql语句。因为这两句sql语句分布在两个不同的sql映射文件,所以两个sql映射文件都需要注册到 全局配置文件中。

6、补充说明

分步查询中:子句查询时(无论是association 还是 collection 标签),传入多个参数问题,延迟加载设置:

### 举例:
### fetchType="lazy" 代表子句执行时,用的是延迟加载。
### - lazy:延迟  
### - eager:立即

### 子查询 多个入参问题
### column="{deptId=id}" 代表 sql字段的 id ,传入给 子句查询中的 deptId 入参
### 将多列的值封装成map;column="{key1=column1,key2=column2}"  来传给子查询的入参

<collection property="employees" 
	select="com.mybatis.mapper.EmployeeMapperPlus.getEmpsByDeptId"
	column="{deptId=id}" fetchType="lazy">
</collection>

 

 

 

mybatis映射文件-(6)-resultMap关联查询之非级联一对多一步查询

前面提到的关联查询中,bean里面的 某个属性就是一个对象,属于 一对一映射:可以采用一步查询,级联赋值 或者  采用分步查询 ,单独赋值。现在如果 bean的某个属性是 一个集合,属于一对多映射,那么 查询结果 就不能用级联赋值了。级联赋值 是 一对一 关系映射中的 一种方法。


1、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

数据库测试:

select  d.id  did, d.dept_name dept_name, e.id eid, e.last_name last_name,
e.email email, e.gender gender
from tbl_dept d
left join tbl_employee e
on d.id = e.d_id
where d.id =1

2、编辑 javabean

Employee.java

package com.mybatis.bean;

public class Employee {
	private int id;
	private String lastName;
	private String email;
	private String gender;
	private Department department;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}

}

Department.java

package com.mybatis.bean;

import java.util.List;

public class Department {
	
	private Integer id;
	private String departmentName;
        private List<Employee> employees;
        
        public List<Employee> getEmployees() {
		return employees;
	}
	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getDepartmentName() {
		return departmentName;
	}
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName
				+ "]";
	}
	
	

}

3、编辑接口文件

DepartmentMapper.java

package com.mybatis.mapper;

import com.mybatis.bean.Department;

public interface DepartmentMapper {
	
	//增强版 还能查出员工
	public Department getDeptByIdPlus(Integer id);

}

4、编辑sql映射文件

DepartmentMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.DepartmentMapper">
	<!-- 
	public class Department {
			private Integer id;
			private String departmentName;
			private List<Employee> emps;
	  did  dept_name  ||  eid  last_name  email   gender  
	 -->
	 
	<!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则  -->
	<resultMap type="com.mybatis.bean.Department" id="MyDept">
		<id column="did" property="id"/>
		<result column="dept_name" property="departmentName"/>
		<!-- 
			collection定义关联集合类型的属性的封装规则 
			ofType:指定集合里面元素的类型
		-->
		<collection property="employees" ofType="com.mybatis.bean.Employee">
			<!-- 定义这个集合中元素的封装规则 -->
			<id column="eid" property="id"/>
			<result column="last_name" property="lastName"/>
			<result column="email" property="email"/>
			<result column="gender" property="gender"/>
		</collection>
	</resultMap>
	<!-- public Department getDeptByIdPlus(Integer id); -->
	<select id="getDeptByIdPlus" resultMap="MyDept">
		SELECT d.id did,d.dept_name dept_name,
				e.id eid,e.last_name last_name,e.email email,e.gender gender
		FROM tbl_dept d
		LEFT JOIN tbl_employee e
		ON d.id=e.d_id
		WHERE d.id=#{id}
	</select>
</mapper>

5、编辑全局配置文件:

mybatis-config.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>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="Kitty521!" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 
	如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
	-->
	<mappers>
		<mapper resource="DepartmentMapper.xml" />
	</mappers>
	
</configuration>

6、单元测试:

MybatisTest.java

package com.mybatis.test;


import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.mybatis.bean.Department;
import com.mybatis.bean.Employee;
import com.mybatis.mapper.DepartmentMapper;
import com.mybatis.mapper.EmployeeMapperPlus;


/**
 * 1、接口式编程
 * 	原生:		Dao		====>  DaoImpl
 * 	mybatis:	Mapper	====>  xxMapper.xml
 * 
 * 2、SqlSession代表和数据库的一次会话;用完必须关闭;
 * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。(就是不要放在共享成员变量里面,A线程用完释放,B线程再用就为空了)
 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
 * 		(将接口和xml进行绑定)
 * 		EmployeeMapper empMapper =	sqlSession.getMapper(EmployeeMapper.class);
 * 5、两个重要的配置文件:
 * 		mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
 * 		sql映射文件:保存了每一个sql语句的映射信息:
 * 					将sql抽取出来。	
 *
 */

public class MybatisTest {


	/********************************************************************/
	
	public SqlSessionFactory getSqlSessionFactory() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		return new SqlSessionFactoryBuilder().build(inputStream);
	}
	
	@Test
	public void test_new() throws IOException {
		// 1、获取sqlSessionFactory对象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 2、获取sqlSession对象
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			// 3、获取接口的实现类对象
			//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法

//			EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
//			Employee employee = mapper.getEmpByIdStep(1);
//			System.out.println(mapper.getClass());
//			System.out.println(employee);
//			System.out.println(employee.getDepartment());
			
			DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
			Department department = mapper.getDeptByIdPlus(1);
			System.out.println(mapper.getClass());
			System.out.println(department);
			System.out.println(department.getEmployees());

		} finally {
			openSession.close();
		}

	}

}